qs 6.5.0 → 6.6.0

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/test/parse.js CHANGED
@@ -4,6 +4,7 @@ var test = require('tape');
4
4
  var qs = require('../');
5
5
  var utils = require('../lib/utils');
6
6
  var iconv = require('iconv-lite');
7
+ var SaferBuffer = require('safer-buffer').Buffer;
7
8
 
8
9
  test('parse()', function (t) {
9
10
  t.test('parses a simple string', function (st) {
@@ -231,7 +232,7 @@ test('parse()', function (t) {
231
232
  });
232
233
 
233
234
  t.test('parses buffers correctly', function (st) {
234
- var b = new Buffer('test');
235
+ var b = SaferBuffer.from('test');
235
236
  st.deepEqual(qs.parse({ a: b }), { a: b });
236
237
  st.end();
237
238
  });
@@ -256,7 +257,7 @@ test('parse()', function (t) {
256
257
  st.end();
257
258
  });
258
259
 
259
- t.test('should not throw when a native prototype has an enumerable property', { parallel: false }, function (st) {
260
+ t.test('should not throw when a native prototype has an enumerable property', function (st) {
260
261
  Object.prototype.crash = '';
261
262
  Array.prototype.crash = '';
262
263
  st.doesNotThrow(qs.parse.bind(null, 'a=b'));
@@ -301,7 +302,14 @@ test('parse()', function (t) {
301
302
  });
302
303
 
303
304
  t.test('allows disabling array parsing', function (st) {
304
- st.deepEqual(qs.parse('a[0]=b&a[1]=c', { parseArrays: false }), { a: { 0: 'b', 1: 'c' } });
305
+ var indices = qs.parse('a[0]=b&a[1]=c', { parseArrays: false });
306
+ st.deepEqual(indices, { a: { 0: 'b', 1: 'c' } });
307
+ st.equal(Array.isArray(indices.a), false, 'parseArrays:false, indices case is not an array');
308
+
309
+ var emptyBrackets = qs.parse('a[]=b', { parseArrays: false });
310
+ st.deepEqual(emptyBrackets, { a: { 0: 'b' } });
311
+ st.equal(Array.isArray(emptyBrackets.a), false, 'parseArrays:false, empty brackets case is not an array');
312
+
305
313
  st.end();
306
314
  });
307
315
 
@@ -396,6 +404,33 @@ test('parse()', function (t) {
396
404
  st.end();
397
405
  });
398
406
 
407
+ t.test('does not crash when parsing deep objects', function (st) {
408
+ var parsed;
409
+ var str = 'foo';
410
+
411
+ for (var i = 0; i < 5000; i++) {
412
+ str += '[p]';
413
+ }
414
+
415
+ str += '=bar';
416
+
417
+ st.doesNotThrow(function () {
418
+ parsed = qs.parse(str, { depth: 5000 });
419
+ });
420
+
421
+ st.equal('foo' in parsed, true, 'parsed has "foo" property');
422
+
423
+ var depth = 0;
424
+ var ref = parsed.foo;
425
+ while ((ref = ref.p)) {
426
+ depth += 1;
427
+ }
428
+
429
+ st.equal(depth, 5000, 'parsed is 5000 properties deep');
430
+
431
+ st.end();
432
+ });
433
+
399
434
  t.test('parses null objects correctly', { skip: !Object.create }, function (st) {
400
435
  var a = Object.create(null);
401
436
  a.b = 'c';
@@ -512,7 +547,7 @@ test('parse()', function (t) {
512
547
  result.push(parseInt(parts[1], 16));
513
548
  parts = reg.exec(str);
514
549
  }
515
- return iconv.decode(new Buffer(result), 'shift_jis').toString();
550
+ return iconv.decode(SaferBuffer.from(result), 'shift_jis').toString();
516
551
  }
517
552
  }), { 県: '大阪府' });
518
553
  st.end();
@@ -529,7 +564,7 @@ test('parse()', function (t) {
529
564
  });
530
565
 
531
566
  t.test('throws error with wrong decoder', function (st) {
532
- st.throws(function () {
567
+ st['throws'](function () {
533
568
  qs.parse({}, { decoder: 'string' });
534
569
  }, new TypeError('Decoder has to be a function.'));
535
570
  st.end();
@@ -542,5 +577,83 @@ test('parse()', function (t) {
542
577
  st.end();
543
578
  });
544
579
 
580
+ t.test('throws if an invalid charset is specified', function (st) {
581
+ st['throws'](function () {
582
+ qs.parse('a=b', { charset: 'foobar' });
583
+ }, new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined'));
584
+ st.end();
585
+ });
586
+
587
+ t.test('parses an iso-8859-1 string if asked to', function (st) {
588
+ st.deepEqual(qs.parse('%A2=%BD', { charset: 'iso-8859-1' }), { '¢': '½' });
589
+ st.end();
590
+ });
591
+
592
+ var urlEncodedCheckmarkInUtf8 = '%E2%9C%93';
593
+ var urlEncodedOSlashInUtf8 = '%C3%B8';
594
+ var urlEncodedNumCheckmark = '%26%2310003%3B';
595
+ var urlEncodedNumSmiley = '%26%239786%3B';
596
+
597
+ t.test('prefers an utf-8 charset specified by the utf8 sentinel to a default charset of iso-8859-1', function (st) {
598
+ st.deepEqual(qs.parse('utf8=' + urlEncodedCheckmarkInUtf8 + '&' + urlEncodedOSlashInUtf8 + '=' + urlEncodedOSlashInUtf8, { charsetSentinel: true, charset: 'iso-8859-1' }), { ø: 'ø' });
599
+ st.end();
600
+ });
601
+
602
+ t.test('prefers an iso-8859-1 charset specified by the utf8 sentinel to a default charset of utf-8', function (st) {
603
+ st.deepEqual(qs.parse('utf8=' + urlEncodedNumCheckmark + '&' + urlEncodedOSlashInUtf8 + '=' + urlEncodedOSlashInUtf8, { charsetSentinel: true, charset: 'utf-8' }), { 'ø': 'ø' });
604
+ st.end();
605
+ });
606
+
607
+ t.test('does not require the utf8 sentinel to be defined before the parameters whose decoding it affects', function (st) {
608
+ st.deepEqual(qs.parse('a=' + urlEncodedOSlashInUtf8 + '&utf8=' + urlEncodedNumCheckmark, { charsetSentinel: true, charset: 'utf-8' }), { a: 'ø' });
609
+ st.end();
610
+ });
611
+
612
+ t.test('should ignore an utf8 sentinel with an unknown value', function (st) {
613
+ st.deepEqual(qs.parse('utf8=foo&' + urlEncodedOSlashInUtf8 + '=' + urlEncodedOSlashInUtf8, { charsetSentinel: true, charset: 'utf-8' }), { ø: 'ø' });
614
+ st.end();
615
+ });
616
+
617
+ t.test('uses the utf8 sentinel to switch to utf-8 when no default charset is given', function (st) {
618
+ st.deepEqual(qs.parse('utf8=' + urlEncodedCheckmarkInUtf8 + '&' + urlEncodedOSlashInUtf8 + '=' + urlEncodedOSlashInUtf8, { charsetSentinel: true }), { ø: 'ø' });
619
+ st.end();
620
+ });
621
+
622
+ t.test('uses the utf8 sentinel to switch to iso-8859-1 when no default charset is given', function (st) {
623
+ st.deepEqual(qs.parse('utf8=' + urlEncodedNumCheckmark + '&' + urlEncodedOSlashInUtf8 + '=' + urlEncodedOSlashInUtf8, { charsetSentinel: true }), { 'ø': 'ø' });
624
+ st.end();
625
+ });
626
+
627
+ t.test('interprets numeric entities in iso-8859-1 when `interpretNumericEntities`', function (st) {
628
+ st.deepEqual(qs.parse('foo=' + urlEncodedNumSmiley, { charset: 'iso-8859-1', interpretNumericEntities: true }), { foo: '☺' });
629
+ st.end();
630
+ });
631
+
632
+ t.test('handles a custom decoder returning `null`, in the `iso-8859-1` charset, when `interpretNumericEntities`', function (st) {
633
+ st.deepEqual(qs.parse('foo=&bar=' + urlEncodedNumSmiley, {
634
+ charset: 'iso-8859-1',
635
+ decoder: function (str, defaultDecoder, charset) {
636
+ return str ? defaultDecoder(str, defaultDecoder, charset) : null;
637
+ },
638
+ interpretNumericEntities: true
639
+ }), { foo: null, bar: '☺' });
640
+ st.end();
641
+ });
642
+
643
+ t.test('does not interpret numeric entities in iso-8859-1 when `interpretNumericEntities` is absent', function (st) {
644
+ st.deepEqual(qs.parse('foo=' + urlEncodedNumSmiley, { charset: 'iso-8859-1' }), { foo: '&#9786;' });
645
+ st.end();
646
+ });
647
+
648
+ t.test('does not interpret numeric entities when the charset is utf-8, even when `interpretNumericEntities`', function (st) {
649
+ st.deepEqual(qs.parse('foo=' + urlEncodedNumSmiley, { charset: 'utf-8', interpretNumericEntities: true }), { foo: '&#9786;' });
650
+ st.end();
651
+ });
652
+
653
+ t.test('does not interpret %uXXXX syntax in iso-8859-1 mode', function (st) {
654
+ st.deepEqual(qs.parse('%u263A=%u263A', { charset: 'iso-8859-1' }), { '%u263A': '%u263A' });
655
+ st.end();
656
+ });
657
+
545
658
  t.end();
546
659
  });
package/test/stringify.js CHANGED
@@ -4,6 +4,7 @@ var test = require('tape');
4
4
  var qs = require('../');
5
5
  var utils = require('../lib/utils');
6
6
  var iconv = require('iconv-lite');
7
+ var SaferBuffer = require('safer-buffer').Buffer;
7
8
 
8
9
  test('stringify()', function (t) {
9
10
  t.test('stringifies a querystring object', function (st) {
@@ -336,8 +337,8 @@ test('stringify()', function (t) {
336
337
  });
337
338
 
338
339
  t.test('stringifies buffer values', function (st) {
339
- st.equal(qs.stringify({ a: new Buffer('test') }), 'a=test');
340
- st.equal(qs.stringify({ a: { b: new Buffer('test') } }), 'a%5Bb%5D=test');
340
+ st.equal(qs.stringify({ a: SaferBuffer.from('test') }), 'a=test');
341
+ st.equal(qs.stringify({ a: { b: SaferBuffer.from('test') } }), 'a%5Bb%5D=test');
341
342
  st.end();
342
343
  });
343
344
 
@@ -474,14 +475,14 @@ test('stringify()', function (t) {
474
475
  });
475
476
 
476
477
  t.test('throws error with wrong encoder', function (st) {
477
- st.throws(function () {
478
+ st['throws'](function () {
478
479
  qs.stringify({}, { encoder: 'string' });
479
480
  }, new TypeError('Encoder has to be a function.'));
480
481
  st.end();
481
482
  });
482
483
 
483
484
  t.test('can use custom encoder for a buffer object', { skip: typeof Buffer === 'undefined' }, function (st) {
484
- st.equal(qs.stringify({ a: new Buffer([1]) }, {
485
+ st.equal(qs.stringify({ a: SaferBuffer.from([1]) }, {
485
486
  encoder: function (buffer) {
486
487
  if (typeof buffer === 'string') {
487
488
  return buffer;
@@ -504,7 +505,7 @@ test('stringify()', function (t) {
504
505
  mutatedDate.toISOString = function () {
505
506
  throw new SyntaxError();
506
507
  };
507
- st.throws(function () {
508
+ st['throws'](function () {
508
509
  mutatedDate.toISOString();
509
510
  }, SyntaxError);
510
511
  st.equal(
@@ -546,7 +547,7 @@ test('stringify()', function (t) {
546
547
  t.test('Edge cases and unknown formats', function (st) {
547
548
  ['UFO1234', false, 1234, null, {}, []].forEach(
548
549
  function (format) {
549
- st.throws(
550
+ st['throws'](
550
551
  function () {
551
552
  qs.stringify({ a: 'b c' }, { format: format });
552
553
  },
@@ -585,6 +586,38 @@ test('stringify()', function (t) {
585
586
  st.end();
586
587
  });
587
588
 
589
+ t.test('throws if an invalid charset is specified', function (st) {
590
+ st['throws'](function () {
591
+ qs.stringify({ a: 'b' }, { charset: 'foobar' });
592
+ }, new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined'));
593
+ st.end();
594
+ });
595
+
596
+ t.test('respects a charset of iso-8859-1', function (st) {
597
+ st.equal(qs.stringify({ æ: 'æ' }, { charset: 'iso-8859-1' }), '%E6=%E6');
598
+ st.end();
599
+ });
600
+
601
+ t.test('encodes unrepresentable chars as numeric entities in iso-8859-1 mode', function (st) {
602
+ st.equal(qs.stringify({ a: '☺' }, { charset: 'iso-8859-1' }), 'a=%26%239786%3B');
603
+ st.end();
604
+ });
605
+
606
+ t.test('respects an explicit charset of utf-8 (the default)', function (st) {
607
+ st.equal(qs.stringify({ a: 'æ' }, { charset: 'utf-8' }), 'a=%C3%A6');
608
+ st.end();
609
+ });
610
+
611
+ t.test('adds the right sentinel when instructed to and the charset is utf-8', function (st) {
612
+ st.equal(qs.stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'utf-8' }), 'utf8=%E2%9C%93&a=%C3%A6');
613
+ st.end();
614
+ });
615
+
616
+ t.test('adds the right sentinel when instructed to and the charset is iso-8859-1', function (st) {
617
+ st.equal(qs.stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'iso-8859-1' }), 'utf8=%26%2310003%3B&a=%E6');
618
+ st.end();
619
+ });
620
+
588
621
  t.test('does not mutate the options argument', function (st) {
589
622
  var options = {};
590
623
  qs.stringify({}, options);
@@ -592,5 +625,25 @@ test('stringify()', function (t) {
592
625
  st.end();
593
626
  });
594
627
 
628
+ t.test('strictNullHandling works with custom filter', function (st) {
629
+ var filter = function (prefix, value) {
630
+ return value;
631
+ };
632
+
633
+ var options = { strictNullHandling: true, filter: filter };
634
+ st.equal(qs.stringify({ key: null }, options), 'key');
635
+ st.end();
636
+ });
637
+
638
+ t.test('strictNullHandling works with null serializeDate', function (st) {
639
+ var serializeDate = function () {
640
+ return null;
641
+ };
642
+ var options = { strictNullHandling: true, serializeDate: serializeDate };
643
+ var date = new Date();
644
+ st.equal(qs.stringify({ key: date }, options), 'key');
645
+ st.end();
646
+ });
647
+
595
648
  t.end();
596
649
  });
package/test/utils.js CHANGED
@@ -18,6 +18,9 @@ test('merge()', function (t) {
18
18
  var nestedArrays = utils.merge({ foo: ['baz'] }, { foo: ['bar', 'xyzzy'] });
19
19
  t.deepEqual(nestedArrays, { foo: ['baz', 'bar', 'xyzzy'] });
20
20
 
21
+ var noOptionsNonObjectSource = utils.merge({ foo: 'baz' }, 'bar');
22
+ t.deepEqual(noOptionsNonObjectSource, { foo: 'baz', bar: true });
23
+
21
24
  t.end();
22
25
  });
23
26
 
@@ -32,3 +35,55 @@ test('assign()', function (t) {
32
35
 
33
36
  t.end();
34
37
  });
38
+
39
+ test('combine()', function (t) {
40
+ t.test('both arrays', function (st) {
41
+ var a = [1];
42
+ var b = [2];
43
+ var combined = utils.combine(a, b);
44
+
45
+ st.deepEqual(a, [1], 'a is not mutated');
46
+ st.deepEqual(b, [2], 'b is not mutated');
47
+ st.notEqual(a, combined, 'a !== combined');
48
+ st.notEqual(b, combined, 'b !== combined');
49
+ st.deepEqual(combined, [1, 2], 'combined is a + b');
50
+
51
+ st.end();
52
+ });
53
+
54
+ t.test('one array, one non-array', function (st) {
55
+ var aN = 1;
56
+ var a = [aN];
57
+ var bN = 2;
58
+ var b = [bN];
59
+
60
+ var combinedAnB = utils.combine(aN, b);
61
+ st.deepEqual(b, [bN], 'b is not mutated');
62
+ st.notEqual(aN, combinedAnB, 'aN + b !== aN');
63
+ st.notEqual(a, combinedAnB, 'aN + b !== a');
64
+ st.notEqual(bN, combinedAnB, 'aN + b !== bN');
65
+ st.notEqual(b, combinedAnB, 'aN + b !== b');
66
+ st.deepEqual([1, 2], combinedAnB, 'first argument is array-wrapped when not an array');
67
+
68
+ var combinedABn = utils.combine(a, bN);
69
+ st.deepEqual(a, [aN], 'a is not mutated');
70
+ st.notEqual(aN, combinedABn, 'a + bN !== aN');
71
+ st.notEqual(a, combinedABn, 'a + bN !== a');
72
+ st.notEqual(bN, combinedABn, 'a + bN !== bN');
73
+ st.notEqual(b, combinedABn, 'a + bN !== b');
74
+ st.deepEqual([1, 2], combinedABn, 'second argument is array-wrapped when not an array');
75
+
76
+ st.end();
77
+ });
78
+
79
+ t.test('neither is an array', function (st) {
80
+ var combined = utils.combine(1, 2);
81
+ st.notEqual(1, combined, '1 + 2 !== 1');
82
+ st.notEqual(2, combined, '1 + 2 !== 2');
83
+ st.deepEqual([1, 2], combined, 'both arguments are array-wrapped when not an array');
84
+
85
+ st.end();
86
+ });
87
+
88
+ t.end();
89
+ });