qs 6.3.1 → 6.4.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/package.json CHANGED
@@ -1,50 +1,54 @@
1
1
  {
2
- "name": "qs",
3
- "description": "A querystring parser that supports nesting and arrays, with a depth limit",
4
- "homepage": "https://github.com/ljharb/qs",
5
- "version": "6.3.1",
6
- "repository": {
7
- "type": "git",
8
- "url": "https://github.com/ljharb/qs.git"
9
- },
10
- "main": "lib/index.js",
11
- "contributors": [
12
- {
13
- "name": "Jordan Harband",
14
- "email": "ljharb@gmail.com",
15
- "url": "http://ljharb.codes"
16
- }
17
- ],
18
- "keywords": [
19
- "querystring",
20
- "qs"
21
- ],
22
- "engines": {
23
- "node": ">=0.6"
24
- },
25
- "dependencies": {},
26
- "devDependencies": {
27
- "@ljharb/eslint-config": "^11.0.0",
28
- "browserify": "^14.1.0",
29
- "covert": "^1.1.0",
30
- "eslint": "^3.15.0",
31
- "evalmd": "^0.0.17",
32
- "iconv-lite": "^0.4.15",
33
- "mkdirp": "^0.5.1",
34
- "parallelshell": "^2.0.0",
35
- "qs-iconv": "^1.0.4",
36
- "safe-publish-latest": "^1.1.1",
37
- "tape": "^4.6.3"
38
- },
39
- "scripts": {
40
- "prepublish": "safe-publish-latest && npm run dist",
41
- "pretest": "npm run --silent readme && npm run --silent lint",
42
- "test": "npm run --silent coverage",
43
- "tests-only": "node test",
44
- "readme": "evalmd README.md",
45
- "lint": "eslint lib/*.js test/*.js",
46
- "coverage": "covert test",
47
- "dist": "mkdirp dist && browserify --standalone Qs lib/index.js > dist/qs.js"
48
- },
49
- "license": "BSD-3-Clause"
2
+ "name": "qs",
3
+ "description": "A querystring parser that supports nesting and arrays, with a depth limit",
4
+ "homepage": "https://github.com/ljharb/qs",
5
+ "version": "6.4.1",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/ljharb/qs.git"
9
+ },
10
+ "main": "lib/index.js",
11
+ "contributors": [
12
+ {
13
+ "name": "Jordan Harband",
14
+ "email": "ljharb@gmail.com",
15
+ "url": "http://ljharb.codes"
16
+ }
17
+ ],
18
+ "keywords": [
19
+ "querystring",
20
+ "qs"
21
+ ],
22
+ "engines": {
23
+ "node": ">=0.6"
24
+ },
25
+ "devDependencies": {
26
+ "@ljharb/eslint-config": "^20.1.0",
27
+ "aud": "^1.1.5",
28
+ "browserify": "^16.5.2",
29
+ "eclint": "^2.8.1",
30
+ "eslint": "^8.6.0",
31
+ "evalmd": "^0.0.17",
32
+ "iconv-lite": "^0.4.24",
33
+ "in-publish": "^2.0.1",
34
+ "mkdirp": "^0.5.1",
35
+ "nyc": "^10.3.2",
36
+ "qs-iconv": "^1.0.4",
37
+ "safe-publish-latest": "^2.0.0",
38
+ "safer-buffer": "^2.1.2",
39
+ "tape": "^5.4.0"
40
+ },
41
+ "scripts": {
42
+ "prepublishOnly": "safe-publish-latest && npm run dist",
43
+ "prepublish": "not-in-publish || npm run prepublishOnly",
44
+ "pretest": "npm run --silent readme && npm run --silent lint",
45
+ "test": "npm run --silent tests-only",
46
+ "tests-only": "nyc tape 'test/**/*.js'",
47
+ "posttest": "aud --production",
48
+ "readme": "evalmd README.md",
49
+ "postlint": "eclint check $(git ls-files | xargs find 2> /dev/null | grep -vE 'node_modules|\\.git')",
50
+ "lint": "eslint --ext=js,mjs .",
51
+ "dist": "mkdirp dist && browserify --standalone Qs lib/index.js > dist/qs.js"
52
+ },
53
+ "license": "BSD-3-Clause"
50
54
  }
package/test/parse.js CHANGED
@@ -3,6 +3,7 @@
3
3
  var test = require('tape');
4
4
  var qs = require('../');
5
5
  var iconv = require('iconv-lite');
6
+ var SaferBuffer = require('safer-buffer').Buffer;
6
7
 
7
8
  test('parse()', function (t) {
8
9
  t.test('parses a simple string', function (st) {
@@ -152,8 +153,6 @@ test('parse()', function (t) {
152
153
  st.end();
153
154
  });
154
155
 
155
- t.deepEqual(qs.parse('a[b]=c&a=d'), { a: { b: 'c', d: true } }, 'can add keys to objects');
156
-
157
156
  t.test('correctly prunes undefined values when converting an array to an object', function (st) {
158
157
  st.deepEqual(qs.parse('a[2]=b&a[99999999]=c'), { a: { 2: 'b', 99999999: 'c' } });
159
158
  st.end();
@@ -232,7 +231,7 @@ test('parse()', function (t) {
232
231
  });
233
232
 
234
233
  t.test('parses buffers correctly', function (st) {
235
- var b = new Buffer('test');
234
+ var b = SaferBuffer.from('test');
236
235
  st.deepEqual(qs.parse({ a: b }), { a: b });
237
236
  st.end();
238
237
  });
@@ -257,7 +256,7 @@ test('parse()', function (t) {
257
256
  st.end();
258
257
  });
259
258
 
260
- t.test('should not throw when a native prototype has an enumerable property', { parallel: false }, function (st) {
259
+ t.test('should not throw when a native prototype has an enumerable property', function (st) {
261
260
  Object.prototype.crash = '';
262
261
  Array.prototype.crash = '';
263
262
  st.doesNotThrow(qs.parse.bind(null, 'a=b'));
@@ -302,7 +301,14 @@ test('parse()', function (t) {
302
301
  });
303
302
 
304
303
  t.test('allows disabling array parsing', function (st) {
305
- st.deepEqual(qs.parse('a[0]=b&a[1]=c', { parseArrays: false }), { a: { 0: 'b', 1: 'c' } });
304
+ var indices = qs.parse('a[0]=b&a[1]=c', { parseArrays: false });
305
+ st.deepEqual(indices, { a: { 0: 'b', 1: 'c' } });
306
+ st.equal(Array.isArray(indices.a), false, 'parseArrays:false, indices case is not an array');
307
+
308
+ var emptyBrackets = qs.parse('a[]=b', { parseArrays: false });
309
+ st.deepEqual(emptyBrackets, { a: { 0: 'b' } });
310
+ st.equal(Array.isArray(emptyBrackets.a), false, 'parseArrays:false, empty brackets case is not an array');
311
+
306
312
  st.end();
307
313
  });
308
314
 
@@ -441,6 +447,103 @@ test('parse()', function (t) {
441
447
 
442
448
  t.test('params starting with a closing bracket', function (st) {
443
449
  st.deepEqual(qs.parse(']=toString'), { ']': 'toString' });
450
+ st.deepEqual(qs.parse(']]=toString'), { ']]': 'toString' });
451
+ st.deepEqual(qs.parse(']hello]=toString'), { ']hello]': 'toString' });
452
+ st.end();
453
+ });
454
+
455
+ t.test('params starting with a starting bracket', function (st) {
456
+ st.deepEqual(qs.parse('[=toString'), { '[': 'toString' });
457
+ st.deepEqual(qs.parse('[[=toString'), { '[[': 'toString' });
458
+ st.deepEqual(qs.parse('[hello[=toString'), { '[hello[': 'toString' });
459
+ st.end();
460
+ });
461
+
462
+ t.test('add keys to objects', function (st) {
463
+ st.deepEqual(
464
+ qs.parse('a[b]=c&a=d'),
465
+ { a: { b: 'c', d: true } },
466
+ 'can add keys to objects'
467
+ );
468
+
469
+ st.deepEqual(
470
+ qs.parse('a[b]=c&a=toString'),
471
+ { a: { b: 'c' } },
472
+ 'can not overwrite prototype'
473
+ );
474
+
475
+ st.deepEqual(
476
+ qs.parse('a[b]=c&a=toString', { allowPrototypes: true }),
477
+ { a: { b: 'c', toString: true } },
478
+ 'can overwrite prototype with allowPrototypes true'
479
+ );
480
+
481
+ st.deepEqual(
482
+ qs.parse('a[b]=c&a=toString', { plainObjects: true }),
483
+ { __proto__: null, a: { __proto__: null, b: 'c', toString: true } },
484
+ 'can overwrite prototype with plainObjects true'
485
+ );
486
+
487
+ st.end();
488
+ });
489
+
490
+ t.test('dunder proto is ignored', function (st) {
491
+ var payload = 'categories[__proto__]=login&categories[__proto__]&categories[length]=42';
492
+ var result = qs.parse(payload, { allowPrototypes: true });
493
+
494
+ st.deepEqual(
495
+ result,
496
+ {
497
+ categories: {
498
+ length: '42'
499
+ }
500
+ },
501
+ 'silent [[Prototype]] payload'
502
+ );
503
+
504
+ var plainResult = qs.parse(payload, { allowPrototypes: true, plainObjects: true });
505
+
506
+ st.deepEqual(
507
+ plainResult,
508
+ {
509
+ __proto__: null,
510
+ categories: {
511
+ __proto__: null,
512
+ length: '42'
513
+ }
514
+ },
515
+ 'silent [[Prototype]] payload: plain objects'
516
+ );
517
+
518
+ var query = qs.parse('categories[__proto__]=cats&categories[__proto__]=dogs&categories[some][json]=toInject', { allowPrototypes: true });
519
+
520
+ st.notOk(Array.isArray(query.categories), 'is not an array');
521
+ st.notOk(query.categories instanceof Array, 'is not instanceof an array');
522
+ st.deepEqual(query.categories, { some: { json: 'toInject' } });
523
+ st.equal(JSON.stringify(query.categories), '{"some":{"json":"toInject"}}', 'stringifies as a non-array');
524
+
525
+ st.deepEqual(
526
+ qs.parse('foo[__proto__][hidden]=value&foo[bar]=stuffs', { allowPrototypes: true }),
527
+ {
528
+ foo: {
529
+ bar: 'stuffs'
530
+ }
531
+ },
532
+ 'hidden values'
533
+ );
534
+
535
+ st.deepEqual(
536
+ qs.parse('foo[__proto__][hidden]=value&foo[bar]=stuffs', { allowPrototypes: true, plainObjects: true }),
537
+ {
538
+ __proto__: null,
539
+ foo: {
540
+ __proto__: null,
541
+ bar: 'stuffs'
542
+ }
543
+ },
544
+ 'hidden values: plain objects'
545
+ );
546
+
444
547
  st.end();
445
548
  });
446
549
 
@@ -469,14 +572,14 @@ test('parse()', function (t) {
469
572
  result.push(parseInt(parts[1], 16));
470
573
  parts = reg.exec(str);
471
574
  }
472
- return iconv.decode(new Buffer(result), 'shift_jis').toString();
575
+ return iconv.decode(SaferBuffer.from(result), 'shift_jis').toString();
473
576
  }
474
577
  }), { 県: '大阪府' });
475
578
  st.end();
476
579
  });
477
580
 
478
581
  t.test('throws error with wrong decoder', function (st) {
479
- st.throws(function () {
582
+ st['throws'](function () {
480
583
  qs.parse({}, { decoder: 'string' });
481
584
  }, new TypeError('Decoder has to be a function.'));
482
585
  st.end();
package/test/stringify.js CHANGED
@@ -3,6 +3,7 @@
3
3
  var test = require('tape');
4
4
  var qs = require('../');
5
5
  var iconv = require('iconv-lite');
6
+ var SaferBuffer = require('safer-buffer').Buffer;
6
7
 
7
8
  test('stringify()', function (t) {
8
9
  t.test('stringifies a querystring object', function (st) {
@@ -325,8 +326,8 @@ test('stringify()', function (t) {
325
326
  });
326
327
 
327
328
  t.test('stringifies buffer values', function (st) {
328
- st.equal(qs.stringify({ a: new Buffer('test') }), 'a=test');
329
- st.equal(qs.stringify({ a: { b: new Buffer('test') } }), 'a%5Bb%5D=test');
329
+ st.equal(qs.stringify({ a: SaferBuffer.from('test') }), 'a=test');
330
+ st.equal(qs.stringify({ a: { b: SaferBuffer.from('test') } }), 'a%5Bb%5D=test');
330
331
  st.end();
331
332
  });
332
333
 
@@ -453,14 +454,14 @@ test('stringify()', function (t) {
453
454
  });
454
455
 
455
456
  t.test('throws error with wrong encoder', function (st) {
456
- st.throws(function () {
457
+ st['throws'](function () {
457
458
  qs.stringify({}, { encoder: 'string' });
458
459
  }, new TypeError('Encoder has to be a function.'));
459
460
  st.end();
460
461
  });
461
462
 
462
463
  t.test('can use custom encoder for a buffer object', { skip: typeof Buffer === 'undefined' }, function (st) {
463
- st.equal(qs.stringify({ a: new Buffer([1]) }, {
464
+ st.equal(qs.stringify({ a: SaferBuffer.from([1]) }, {
464
465
  encoder: function (buffer) {
465
466
  if (typeof buffer === 'string') {
466
467
  return buffer;
@@ -468,6 +469,12 @@ test('stringify()', function (t) {
468
469
  return String.fromCharCode(buffer.readUInt8(0) + 97);
469
470
  }
470
471
  }), 'a=b');
472
+
473
+ st.equal(qs.stringify({ a: SaferBuffer.from('a b') }, {
474
+ encoder: function (buffer) {
475
+ return buffer;
476
+ }
477
+ }), 'a=a b');
471
478
  st.end();
472
479
  });
473
480
 
@@ -483,7 +490,7 @@ test('stringify()', function (t) {
483
490
  mutatedDate.toISOString = function () {
484
491
  throw new SyntaxError();
485
492
  };
486
- st.throws(function () {
493
+ st['throws'](function () {
487
494
  mutatedDate.toISOString();
488
495
  }, SyntaxError);
489
496
  st.equal(
@@ -508,24 +515,27 @@ test('stringify()', function (t) {
508
515
  t.test('RFC 1738 spaces serialization', function (st) {
509
516
  st.equal(qs.stringify({ a: 'b c' }, { format: qs.formats.RFC1738 }), 'a=b+c');
510
517
  st.equal(qs.stringify({ 'a b': 'c d' }, { format: qs.formats.RFC1738 }), 'a+b=c+d');
518
+ st.equal(qs.stringify({ 'a b': SaferBuffer.from('a b') }, { format: qs.formats.RFC1738 }), 'a+b=a+b');
511
519
  st.end();
512
520
  });
513
521
 
514
522
  t.test('RFC 3986 spaces serialization', function (st) {
515
523
  st.equal(qs.stringify({ a: 'b c' }, { format: qs.formats.RFC3986 }), 'a=b%20c');
516
524
  st.equal(qs.stringify({ 'a b': 'c d' }, { format: qs.formats.RFC3986 }), 'a%20b=c%20d');
525
+ st.equal(qs.stringify({ 'a b': SaferBuffer.from('a b') }, { format: qs.formats.RFC3986 }), 'a%20b=a%20b');
517
526
  st.end();
518
527
  });
519
528
 
520
529
  t.test('Backward compatibility to RFC 3986', function (st) {
521
530
  st.equal(qs.stringify({ a: 'b c' }), 'a=b%20c');
531
+ st.equal(qs.stringify({ 'a b': SaferBuffer.from('a b') }), 'a%20b=a%20b');
522
532
  st.end();
523
533
  });
524
534
 
525
535
  t.test('Edge cases and unknown formats', function (st) {
526
536
  ['UFO1234', false, 1234, null, {}, []].forEach(
527
537
  function (format) {
528
- st.throws(
538
+ st['throws'](
529
539
  function () {
530
540
  qs.stringify({ a: 'b c' }, { format: format });
531
541
  },
@@ -535,4 +545,54 @@ test('stringify()', function (t) {
535
545
  );
536
546
  st.end();
537
547
  });
548
+
549
+ t.test('encodeValuesOnly', function (st) {
550
+ st.equal(
551
+ qs.stringify(
552
+ { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
553
+ { encodeValuesOnly: true }
554
+ ),
555
+ 'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h'
556
+ );
557
+ st.equal(
558
+ qs.stringify(
559
+ { a: 'b', c: ['d', 'e'], f: [['g'], ['h']] }
560
+ ),
561
+ 'a=b&c%5B0%5D=d&c%5B1%5D=e&f%5B0%5D%5B0%5D=g&f%5B1%5D%5B0%5D=h'
562
+ );
563
+ st.end();
564
+ });
565
+
566
+ t.test('encodeValuesOnly - strictNullHandling', function (st) {
567
+ st.equal(
568
+ qs.stringify(
569
+ { a: { b: null } },
570
+ { encodeValuesOnly: true, strictNullHandling: true }
571
+ ),
572
+ 'a[b]'
573
+ );
574
+ st.end();
575
+ });
576
+
577
+ t.test('strictNullHandling works with custom filter', function (st) {
578
+ var filter = function (prefix, value) {
579
+ return value;
580
+ };
581
+
582
+ var options = { strictNullHandling: true, filter: filter };
583
+ st.equal(qs.stringify({ key: null }, options), 'key');
584
+ st.end();
585
+ });
586
+
587
+ t.test('strictNullHandling works with null serializeDate', function (st) {
588
+ var serializeDate = function () {
589
+ return null;
590
+ };
591
+ var options = { strictNullHandling: true, serializeDate: serializeDate };
592
+ var date = new Date();
593
+ st.equal(qs.stringify({ key: date }, options), 'key');
594
+ st.end();
595
+ });
596
+
597
+ t.end();
538
598
  });
package/test/utils.js CHANGED
@@ -4,6 +4,10 @@ var test = require('tape');
4
4
  var utils = require('../lib/utils');
5
5
 
6
6
  test('merge()', function (t) {
7
+ t.deepEqual(utils.merge(null, true), [null, true], 'merges true into null');
8
+
9
+ t.deepEqual(utils.merge(null, [42]), [null, 42], 'merges null into an array');
10
+
7
11
  t.deepEqual(utils.merge({ a: 'b' }, { a: 'c' }), { a: ['b', 'c'] }, 'merges two objects with the same key');
8
12
 
9
13
  var oneMerged = utils.merge({ foo: 'bar' }, { foo: { first: '123' } });
@@ -18,5 +22,8 @@ test('merge()', function (t) {
18
22
  var nestedArrays = utils.merge({ foo: ['baz'] }, { foo: ['bar', 'xyzzy'] });
19
23
  t.deepEqual(nestedArrays, { foo: ['baz', 'bar', 'xyzzy'] });
20
24
 
25
+ var noOptionsNonObjectSource = utils.merge({ foo: 'baz' }, 'bar');
26
+ t.deepEqual(noOptionsNonObjectSource, { foo: 'baz', bar: true });
27
+
21
28
  t.end();
22
29
  });
package/.eslintignore DELETED
@@ -1 +0,0 @@
1
- dist
package/LICENSE DELETED
@@ -1,28 +0,0 @@
1
- Copyright (c) 2014 Nathan LaFreniere and other contributors.
2
- All rights reserved.
3
-
4
- Redistribution and use in source and binary forms, with or without
5
- modification, are permitted provided that the following conditions are met:
6
- * Redistributions of source code must retain the above copyright
7
- notice, this list of conditions and the following disclaimer.
8
- * Redistributions in binary form must reproduce the above copyright
9
- notice, this list of conditions and the following disclaimer in the
10
- documentation and/or other materials provided with the distribution.
11
- * The names of any contributors may not be used to endorse or promote
12
- products derived from this software without specific prior written
13
- permission.
14
-
15
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY
19
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
-
26
- * * *
27
-
28
- The complete list of contributors can be found at: https://github.com/hapijs/qs/graphs/contributors
package/test/.eslintrc DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "rules": {
3
- "consistent-return": 2,
4
- "max-lines": 0,
5
- "max-nested-callbacks": [2, 3],
6
- "max-statements": 0,
7
- "no-extend-native": 0,
8
- "sort-keys": 1
9
- }
10
- }