qs 6.8.0 → 6.9.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/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## **6.9.0**
2
+ - [New] `parse`/`stringify`: Pass extra key/value argument to `decoder` (#333)
3
+ - [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `evalmd`
4
+ - [Tests] `parse`: add passing `arrayFormat` tests
5
+ - [Tests] add `posttest` using `npx aud` to run `npm audit` without a lockfile
6
+ - [Tests] up to `node` `v12.10`, `v11.15`, `v10.16`, `v8.16`
7
+ - [Tests] `Buffer.from` in node v5.0-v5.9 and v4.0-v4.4 requires a TypedArray
8
+
1
9
  ## **6.8.0**
2
10
  - [New] add `depth=false` to preserve the original key; [Fix] `depth=0` should preserve the original key (#326)
3
11
  - [New] [Fix] stringify symbols and bigints
package/README.md CHANGED
@@ -330,6 +330,30 @@ var decoded = qs.parse('x=z', { decoder: function (str) {
330
330
  }})
331
331
  ```
332
332
 
333
+ You can encode keys and values using different logic by using the type argument provided to the encoder:
334
+
335
+ ```javascript
336
+ var encoded = qs.stringify({ a: { b: 'c' } }, { encoder: function (str, defaultEncoder, charset, type) {
337
+ if (type === 'key') {
338
+ return // Encoded key
339
+ } else if (type === 'value') {
340
+ return // Encoded value
341
+ }
342
+ }})
343
+ ```
344
+
345
+ The type argument is also provided to the decoder:
346
+
347
+ ```javascript
348
+ var decoded = qs.parse('x=z', { decoder: function (str, defaultEncoder, charset, type) {
349
+ if (type === 'key') {
350
+ return // Decoded key
351
+ } else if (type === 'value') {
352
+ return // Decoded value
353
+ }
354
+ }})
355
+ ```
356
+
333
357
  Examples beyond this point will be shown as though the output is not URI encoded for clarity. Please note that the return values in these cases *will* be URI encoded during real usage.
334
358
 
335
359
  When arrays are stringified, by default they are given explicit indices:
package/dist/qs.js CHANGED
@@ -114,11 +114,11 @@ var parseValues = function parseQueryStringValues(str, options) {
114
114
 
115
115
  var key, val;
116
116
  if (pos === -1) {
117
- key = options.decoder(part, defaults.decoder, charset);
117
+ key = options.decoder(part, defaults.decoder, charset, 'key');
118
118
  val = options.strictNullHandling ? null : '';
119
119
  } else {
120
- key = options.decoder(part.slice(0, pos), defaults.decoder, charset);
121
- val = options.decoder(part.slice(pos + 1), defaults.decoder, charset);
120
+ key = options.decoder(part.slice(0, pos), defaults.decoder, charset, 'key');
121
+ val = options.decoder(part.slice(pos + 1), defaults.decoder, charset, 'value');
122
122
  }
123
123
 
124
124
  if (val && options.interpretNumericEntities && charset === 'iso-8859-1') {
@@ -292,14 +292,14 @@ var formats = require('./formats');
292
292
  var has = Object.prototype.hasOwnProperty;
293
293
 
294
294
  var arrayPrefixGenerators = {
295
- brackets: function brackets(prefix) { // eslint-disable-line func-name-matching
295
+ brackets: function brackets(prefix) {
296
296
  return prefix + '[]';
297
297
  },
298
298
  comma: 'comma',
299
- indices: function indices(prefix, key) { // eslint-disable-line func-name-matching
299
+ indices: function indices(prefix, key) {
300
300
  return prefix + '[' + key + ']';
301
301
  },
302
- repeat: function repeat(prefix) { // eslint-disable-line func-name-matching
302
+ repeat: function repeat(prefix) {
303
303
  return prefix;
304
304
  }
305
305
  };
@@ -326,22 +326,22 @@ var defaults = {
326
326
  formatter: formats.formatters[defaultFormat],
327
327
  // deprecated
328
328
  indices: false,
329
- serializeDate: function serializeDate(date) { // eslint-disable-line func-name-matching
329
+ serializeDate: function serializeDate(date) {
330
330
  return toISO.call(date);
331
331
  },
332
332
  skipNulls: false,
333
333
  strictNullHandling: false
334
334
  };
335
335
 
336
- var isNonNullishPrimitive = function isNonNullishPrimitive(v) { // eslint-disable-line func-name-matching
336
+ var isNonNullishPrimitive = function isNonNullishPrimitive(v) {
337
337
  return typeof v === 'string'
338
338
  || typeof v === 'number'
339
339
  || typeof v === 'boolean'
340
340
  || typeof v === 'symbol'
341
- || typeof v === 'bigint'; // eslint-disable-line valid-typeof
341
+ || typeof v === 'bigint';
342
342
  };
343
343
 
344
- var stringify = function stringify( // eslint-disable-line func-name-matching
344
+ var stringify = function stringify(
345
345
  object,
346
346
  prefix,
347
347
  generateArrayPrefix,
@@ -367,7 +367,7 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
367
367
 
368
368
  if (obj === null) {
369
369
  if (strictNullHandling) {
370
- return encoder && !encodeValuesOnly ? encoder(prefix, defaults.encoder, charset) : prefix;
370
+ return encoder && !encodeValuesOnly ? encoder(prefix, defaults.encoder, charset, 'key') : prefix;
371
371
  }
372
372
 
373
373
  obj = '';
@@ -375,8 +375,8 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
375
375
 
376
376
  if (isNonNullishPrimitive(obj) || utils.isBuffer(obj)) {
377
377
  if (encoder) {
378
- var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset);
379
- return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder, charset))];
378
+ var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset, 'key');
379
+ return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder, charset, 'value'))];
380
380
  }
381
381
  return [formatter(prefix) + '=' + formatter(String(obj))];
382
382
  }
package/lib/parse.js CHANGED
@@ -72,11 +72,11 @@ var parseValues = function parseQueryStringValues(str, options) {
72
72
 
73
73
  var key, val;
74
74
  if (pos === -1) {
75
- key = options.decoder(part, defaults.decoder, charset);
75
+ key = options.decoder(part, defaults.decoder, charset, 'key');
76
76
  val = options.strictNullHandling ? null : '';
77
77
  } else {
78
- key = options.decoder(part.slice(0, pos), defaults.decoder, charset);
79
- val = options.decoder(part.slice(pos + 1), defaults.decoder, charset);
78
+ key = options.decoder(part.slice(0, pos), defaults.decoder, charset, 'key');
79
+ val = options.decoder(part.slice(pos + 1), defaults.decoder, charset, 'value');
80
80
  }
81
81
 
82
82
  if (val && options.interpretNumericEntities && charset === 'iso-8859-1') {
package/lib/stringify.js CHANGED
@@ -5,14 +5,14 @@ var formats = require('./formats');
5
5
  var has = Object.prototype.hasOwnProperty;
6
6
 
7
7
  var arrayPrefixGenerators = {
8
- brackets: function brackets(prefix) { // eslint-disable-line func-name-matching
8
+ brackets: function brackets(prefix) {
9
9
  return prefix + '[]';
10
10
  },
11
11
  comma: 'comma',
12
- indices: function indices(prefix, key) { // eslint-disable-line func-name-matching
12
+ indices: function indices(prefix, key) {
13
13
  return prefix + '[' + key + ']';
14
14
  },
15
- repeat: function repeat(prefix) { // eslint-disable-line func-name-matching
15
+ repeat: function repeat(prefix) {
16
16
  return prefix;
17
17
  }
18
18
  };
@@ -39,22 +39,22 @@ var defaults = {
39
39
  formatter: formats.formatters[defaultFormat],
40
40
  // deprecated
41
41
  indices: false,
42
- serializeDate: function serializeDate(date) { // eslint-disable-line func-name-matching
42
+ serializeDate: function serializeDate(date) {
43
43
  return toISO.call(date);
44
44
  },
45
45
  skipNulls: false,
46
46
  strictNullHandling: false
47
47
  };
48
48
 
49
- var isNonNullishPrimitive = function isNonNullishPrimitive(v) { // eslint-disable-line func-name-matching
49
+ var isNonNullishPrimitive = function isNonNullishPrimitive(v) {
50
50
  return typeof v === 'string'
51
51
  || typeof v === 'number'
52
52
  || typeof v === 'boolean'
53
53
  || typeof v === 'symbol'
54
- || typeof v === 'bigint'; // eslint-disable-line valid-typeof
54
+ || typeof v === 'bigint';
55
55
  };
56
56
 
57
- var stringify = function stringify( // eslint-disable-line func-name-matching
57
+ var stringify = function stringify(
58
58
  object,
59
59
  prefix,
60
60
  generateArrayPrefix,
@@ -80,7 +80,7 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
80
80
 
81
81
  if (obj === null) {
82
82
  if (strictNullHandling) {
83
- return encoder && !encodeValuesOnly ? encoder(prefix, defaults.encoder, charset) : prefix;
83
+ return encoder && !encodeValuesOnly ? encoder(prefix, defaults.encoder, charset, 'key') : prefix;
84
84
  }
85
85
 
86
86
  obj = '';
@@ -88,8 +88,8 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
88
88
 
89
89
  if (isNonNullishPrimitive(obj) || utils.isBuffer(obj)) {
90
90
  if (encoder) {
91
- var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset);
92
- return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder, charset))];
91
+ var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset, 'key');
92
+ return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder, charset, 'value'))];
93
93
  }
94
94
  return [formatter(prefix) + '=' + formatter(String(obj))];
95
95
  }
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.8.0",
5
+ "version": "6.9.0",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "https://github.com/ljharb/qs.git"
@@ -28,12 +28,12 @@
28
28
  },
29
29
  "dependencies": {},
30
30
  "devDependencies": {
31
- "@ljharb/eslint-config": "^14.0.2",
31
+ "@ljharb/eslint-config": "^14.1.0",
32
32
  "browserify": "^16.5.0",
33
33
  "covert": "^1.1.1",
34
34
  "eclint": "^2.8.1",
35
- "eslint": "^6.1.0",
36
- "evalmd": "^0.0.17",
35
+ "eslint": "^6.4.0",
36
+ "evalmd": "^0.0.19",
37
37
  "for-each": "^0.3.3",
38
38
  "has-symbols": "^1.0.0",
39
39
  "iconv-lite": "^0.4.24",
@@ -49,6 +49,7 @@
49
49
  "pretest": "npm run --silent readme && npm run --silent lint",
50
50
  "test": "npm run --silent coverage",
51
51
  "tests-only": "node test",
52
+ "posttest": "npx aud",
52
53
  "readme": "evalmd README.md",
53
54
  "postlint": "eclint check * lib/* test/*",
54
55
  "lint": "eslint lib/*.js test/*.js",
package/test/.eslintrc CHANGED
@@ -11,7 +11,8 @@
11
11
  "no-buffer-constructor": 0,
12
12
  "no-extend-native": 0,
13
13
  "no-magic-numbers": 0,
14
+ "no-throw-literal": 0,
14
15
  "object-curly-newline": 0,
15
- "sort-keys": 0
16
+ "sort-keys": 0,
16
17
  }
17
18
  }
package/test/parse.js CHANGED
@@ -32,6 +32,38 @@ test('parse()', function (t) {
32
32
  st.end();
33
33
  });
34
34
 
35
+ t.test('arrayFormat: brackets allows only explicit arrays', function (st) {
36
+ st.deepEqual(qs.parse('a[]=b&a[]=c', { arrayFormat: 'brackets' }), { a: ['b', 'c'] });
37
+ st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayFormat: 'brackets' }), { a: ['b', 'c'] });
38
+ st.deepEqual(qs.parse('a=b,c', { arrayFormat: 'brackets' }), { a: 'b,c' });
39
+ st.deepEqual(qs.parse('a=b&a=c', { arrayFormat: 'brackets' }), { a: ['b', 'c'] });
40
+ st.end();
41
+ });
42
+
43
+ t.test('arrayFormat: indices allows only indexed arrays', function (st) {
44
+ st.deepEqual(qs.parse('a[]=b&a[]=c', { arrayFormat: 'indices' }), { a: ['b', 'c'] });
45
+ st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayFormat: 'indices' }), { a: ['b', 'c'] });
46
+ st.deepEqual(qs.parse('a=b,c', { arrayFormat: 'indices' }), { a: 'b,c' });
47
+ st.deepEqual(qs.parse('a=b&a=c', { arrayFormat: 'indices' }), { a: ['b', 'c'] });
48
+ st.end();
49
+ });
50
+
51
+ t.test('arrayFormat: comma allows only comma-separated arrays', function (st) {
52
+ st.deepEqual(qs.parse('a[]=b&a[]=c', { arrayFormat: 'comma' }), { a: ['b', 'c'] });
53
+ st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayFormat: 'comma' }), { a: ['b', 'c'] });
54
+ st.deepEqual(qs.parse('a=b,c', { arrayFormat: 'comma' }), { a: 'b,c' });
55
+ st.deepEqual(qs.parse('a=b&a=c', { arrayFormat: 'comma' }), { a: ['b', 'c'] });
56
+ st.end();
57
+ });
58
+
59
+ t.test('arrayFormat: repeat allows only repeated values', function (st) {
60
+ st.deepEqual(qs.parse('a[]=b&a[]=c', { arrayFormat: 'repeat' }), { a: ['b', 'c'] });
61
+ st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayFormat: 'repeat' }), { a: ['b', 'c'] });
62
+ st.deepEqual(qs.parse('a=b,c', { arrayFormat: 'repeat' }), { a: 'b,c' });
63
+ st.deepEqual(qs.parse('a=b&a=c', { arrayFormat: 'repeat' }), { a: ['b', 'c'] });
64
+ st.end();
65
+ });
66
+
35
67
  t.test('allows enabling dot notation', function (st) {
36
68
  st.deepEqual(qs.parse('a.b=c'), { 'a.b': 'c' });
37
69
  st.deepEqual(qs.parse('a.b=c', { allowDots: true }), { a: { b: 'c' } });
@@ -629,7 +661,6 @@ test('parse()', function (t) {
629
661
  });
630
662
 
631
663
  t.test('prefers an iso-8859-1 charset specified by the utf8 sentinel to a default charset of utf-8', function (st) {
632
- // eslint-disable-next-line quote-props
633
664
  st.deepEqual(qs.parse('utf8=' + urlEncodedNumCheckmark + '&' + urlEncodedOSlashInUtf8 + '=' + urlEncodedOSlashInUtf8, { charsetSentinel: true, charset: 'utf-8' }), { 'ø': 'ø' });
634
665
  st.end();
635
666
  });
@@ -650,7 +681,6 @@ test('parse()', function (t) {
650
681
  });
651
682
 
652
683
  t.test('uses the utf8 sentinel to switch to iso-8859-1 when no default charset is given', function (st) {
653
- // eslint-disable-next-line quote-props
654
684
  st.deepEqual(qs.parse('utf8=' + urlEncodedNumCheckmark + '&' + urlEncodedOSlashInUtf8 + '=' + urlEncodedOSlashInUtf8, { charsetSentinel: true }), { 'ø': 'ø' });
655
685
  st.end();
656
686
  });
@@ -686,5 +716,20 @@ test('parse()', function (t) {
686
716
  st.end();
687
717
  });
688
718
 
719
+ t.test('allows for decoding keys and values differently', function (st) {
720
+ var decoder = function (str, defaultDecoder, charset, type) {
721
+ if (type === 'key') {
722
+ return defaultDecoder(str, defaultDecoder, charset, type).toLowerCase();
723
+ }
724
+ if (type === 'value') {
725
+ return defaultDecoder(str, defaultDecoder, charset, type).toUpperCase();
726
+ }
727
+ throw 'this should never happen! type: ' + type;
728
+ };
729
+
730
+ st.deepEqual(qs.parse('KeY=vAlUe', { decoder: decoder }), { key: 'VALUE' });
731
+ st.end();
732
+ });
733
+
689
734
  t.end();
690
735
  });
package/test/stringify.js CHANGED
@@ -42,10 +42,10 @@ test('stringify()', function (t) {
42
42
  });
43
43
 
44
44
  t.test('stringifies bigints', { skip: !hasBigInt }, function (st) {
45
- var three = BigInt(3); // eslint-disable-line new-cap
45
+ var three = BigInt(3);
46
46
  var encodeWithN = function (value, defaultEncoder, charset) {
47
47
  var result = defaultEncoder(value, defaultEncoder, charset);
48
- return typeof value === 'bigint' ? result + 'n' : result; // eslint-disable-line valid-typeof
48
+ return typeof value === 'bigint' ? result + 'n' : result;
49
49
  };
50
50
  st.equal(qs.stringify(three), '');
51
51
  st.equal(qs.stringify([three]), '0=3');
@@ -719,5 +719,20 @@ test('stringify()', function (t) {
719
719
  st.end();
720
720
  });
721
721
 
722
+ t.test('allows for encoding keys and values differently', function (st) {
723
+ var encoder = function (str, defaultEncoder, charset, type) {
724
+ if (type === 'key') {
725
+ return defaultEncoder(str, defaultEncoder, charset, type).toLowerCase();
726
+ }
727
+ if (type === 'value') {
728
+ return defaultEncoder(str, defaultEncoder, charset, type).toUpperCase();
729
+ }
730
+ throw 'this should never happen! type: ' + type;
731
+ };
732
+
733
+ st.deepEqual(qs.stringify({ KeY: 'vAlUe' }, { encoder: encoder }), 'key=VALUE');
734
+ st.end();
735
+ });
736
+
722
737
  t.end();
723
738
  });
package/test/utils.js CHANGED
@@ -130,7 +130,7 @@ test('isBuffer()', function (t) {
130
130
  var saferBuffer = SaferBuffer.from('abc');
131
131
  t.equal(utils.isBuffer(saferBuffer), true, 'SaferBuffer instance is a buffer');
132
132
 
133
- var buffer = Buffer.from ? Buffer.from('abc') : new Buffer('abc');
133
+ var buffer = Buffer.from && Buffer.alloc ? Buffer.from('abc') : new Buffer('abc');
134
134
  t.equal(utils.isBuffer(buffer), true, 'real Buffer instance is a buffer');
135
135
  t.end();
136
136
  });