qs 6.8.3 → 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/.editorconfig CHANGED
@@ -8,7 +8,6 @@ charset = utf-8
8
8
  trim_trailing_whitespace = true
9
9
  insert_final_newline = true
10
10
  max_line_length = 160
11
- quote_type = single
12
11
 
13
12
  [test/*]
14
13
  max_line_length = off
package/.eslintignore ADDED
@@ -0,0 +1 @@
1
+ dist
package/.eslintrc CHANGED
@@ -3,14 +3,10 @@
3
3
 
4
4
  "extends": "@ljharb",
5
5
 
6
- "ignorePatterns": [
7
- "dist/",
8
- ],
9
-
10
6
  "rules": {
11
7
  "complexity": 0,
12
8
  "consistent-return": 1,
13
- "func-name-matching": 0,
9
+ "func-name-matching": 0,
14
10
  "id-length": [2, { "min": 1, "max": 25, "properties": "never" }],
15
11
  "indent": [2, 4],
16
12
  "max-lines-per-function": [2, { "max": 150 }],
@@ -20,17 +16,6 @@
20
16
  "no-continue": 1,
21
17
  "no-magic-numbers": 0,
22
18
  "no-restricted-syntax": [2, "BreakStatement", "DebuggerStatement", "ForInStatement", "LabeledStatement", "WithStatement"],
23
- },
24
-
25
- "overrides": [
26
- {
27
- "files": "test/**",
28
- "rules": {
29
- "function-paren-newline": 0,
30
- "max-lines-per-function": 0,
31
- "max-statements": 0,
32
- "no-extend-native": 0,
33
- },
34
- },
35
- ],
19
+ "operator-linebreak": [2, "before"],
20
+ }
36
21
  }
package/CHANGELOG.md CHANGED
@@ -1,32 +1,10 @@
1
- ## **6.8.3**
2
- - [Fix] `parse`: ignore `__proto__` keys (#428)
3
- - [Robustness] `stringify`: avoid relying on a global `undefined` (#427)
4
- - [Fix] `stringify`: avoid encoding arrayformat comma when `encodeValuesOnly = true` (#424)
5
- - [readme] remove travis badge; add github actions/codecov badges; update URLs
6
- - [Tests] clean up stringify tests slightly
7
- - [Docs] add note and links for coercing primitive values (#408)
8
- - [meta] fix README.md (#399)
9
- - [actions] backport actions from main
10
- - [Dev Deps] backport updates from main
11
- - [Refactor] `stringify`: reduce branching
12
- - [meta] do not publish workflow files
13
-
14
- ## **6.8.2**
15
- - [Fix] proper comma parsing of URL-encoded commas (#361)
16
- - [Fix] parses comma delimited array while having percent-encoded comma treated as normal text (#336)
17
-
18
- ## **6.8.1**
19
- - [Fix] `parse`: Fix parsing array from object with `comma` true (#359)
20
- - [Fix] `parse`: throw a TypeError instead of an Error for bad charset (#349)
21
- - [Fix] `parse`: with comma true, handle field that holds an array of arrays (#335)
22
- - [fix] `parse`: with comma true, do not split non-string values (#334)
23
- - [meta] add tidelift marketing copy
24
- - [meta] add `funding` field
25
- - [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `tape`, `safe-publish-latest`, `evalmd`, `has-symbols`, `iconv-lite`, `mkdirp`, `object-inspect`
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`
26
4
  - [Tests] `parse`: add passing `arrayFormat` tests
27
- - [Tests] use shared travis-ci configs
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`
28
7
  - [Tests] `Buffer.from` in node v5.0-v5.9 and v4.0-v4.4 requires a TypedArray
29
- - [actions] add automatic rebasing / merge commit blocking
30
8
 
31
9
  ## **6.8.0**
32
10
  - [New] add `depth=false` to preserve the original key; [Fix] `depth=0` should preserve the original key (#326)
package/README.md CHANGED
@@ -1,13 +1,12 @@
1
1
  # qs <sup>[![Version Badge][2]][1]</sup>
2
2
 
3
- [![github actions][actions-image]][actions-url]
4
- [![coverage][codecov-image]][codecov-url]
5
- [![dependency status][deps-svg]][deps-url]
6
- [![dev dependency status][dev-deps-svg]][dev-deps-url]
3
+ [![Build Status][3]][4]
4
+ [![dependency status][5]][6]
5
+ [![dev dependency status][7]][8]
7
6
  [![License][license-image]][license-url]
8
7
  [![Downloads][downloads-image]][downloads-url]
9
8
 
10
- [![npm badge][npm-badge-png]][package-url]
9
+ [![npm badge][11]][1]
11
10
 
12
11
  A querystring parsing and stringifying library with some added security.
13
12
 
@@ -281,17 +280,6 @@ assert.deepEqual(arraysOfObjects, { a: ['b', 'c'] })
281
280
  ```
282
281
  (_this cannot convert nested objects, such as `a={b:1},{c:d}`_)
283
282
 
284
- ### Parsing primitive/scalar values (numbers, booleans, null, etc)
285
-
286
- By default, all values are parsed as strings. This behavior will not change and is explained in [issue #91](https://github.com/ljharb/qs/issues/91).
287
-
288
- ```javascript
289
- var primitiveValues = qs.parse('a=15&b=true&c=null');
290
- assert.deepEqual(primitiveValues, { a: '15', b: 'true', c: 'null' });
291
- ```
292
-
293
- If you wish to auto-convert values which look like numbers, booleans, and other values into their primitive counterparts, you can use the [query-types Express JS middleware](https://github.com/xpepermint/query-types) which will auto-convert all request query parameters.
294
-
295
283
  ### Stringifying
296
284
 
297
285
  [](#preventEval)
@@ -357,7 +345,7 @@ var encoded = qs.stringify({ a: { b: 'c' } }, { encoder: function (str, defaultE
357
345
  The type argument is also provided to the decoder:
358
346
 
359
347
  ```javascript
360
- var decoded = qs.parse('x=z', { decoder: function (str, defaultDecoder, charset, type) {
348
+ var decoded = qs.parse('x=z', { decoder: function (str, defaultEncoder, charset, type) {
361
349
  if (type === 'key') {
362
350
  return // Decoded key
363
351
  } else if (type === 'value') {
@@ -593,24 +581,18 @@ assert.equal(qs.stringify({ a: 'b c' }, { format : 'RFC1738' }), 'a=b+c');
593
581
 
594
582
  Please email [@ljharb](https://github.com/ljharb) or see https://tidelift.com/security if you have a potential security vulnerability to report.
595
583
 
596
- ## qs for enterprise
597
-
598
- Available as part of the Tidelift Subscription
599
-
600
- The maintainers of qs and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-qs?utm_source=npm-qs&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
601
-
602
- [package-url]: https://npmjs.org/package/qs
603
- [npm-version-svg]: https://versionbadg.es/ljharb/qs.svg
604
- [deps-svg]: https://david-dm.org/ljharb/qs.svg
605
- [deps-url]: https://david-dm.org/ljharb/qs
606
- [dev-deps-svg]: https://david-dm.org/ljharb/qs/dev-status.svg
607
- [dev-deps-url]: https://david-dm.org/ljharb/qs#info=devDependencies
608
- [npm-badge-png]: https://nodei.co/npm/qs.png?downloads=true&stars=true
609
- [license-image]: https://img.shields.io/npm/l/qs.svg
584
+ [1]: https://npmjs.org/package/qs
585
+ [2]: http://versionbadg.es/ljharb/qs.svg
586
+ [3]: https://api.travis-ci.org/ljharb/qs.svg
587
+ [4]: https://travis-ci.org/ljharb/qs
588
+ [5]: https://david-dm.org/ljharb/qs.svg
589
+ [6]: https://david-dm.org/ljharb/qs
590
+ [7]: https://david-dm.org/ljharb/qs/dev-status.svg
591
+ [8]: https://david-dm.org/ljharb/qs?type=dev
592
+ [9]: https://ci.testling.com/ljharb/qs.png
593
+ [10]: https://ci.testling.com/ljharb/qs
594
+ [11]: https://nodei.co/npm/qs.png?downloads=true&stars=true
595
+ [license-image]: http://img.shields.io/npm/l/qs.svg
610
596
  [license-url]: LICENSE
611
- [downloads-image]: https://img.shields.io/npm/dm/qs.svg
612
- [downloads-url]: https://npm-stat.com/charts.html?package=qs
613
- [codecov-image]: https://codecov.io/gh/ljharb/qs/branch/main/graphs/badge.svg
614
- [codecov-url]: https://app.codecov.io/gh/ljharb/qs/
615
- [actions-image]: https://img.shields.io/endpoint?url=https://github-actions-badge-u3jn4tfpocch.runkit.sh/ljharb/qs
616
- [actions-url]: https://github.com/ljharb/qs/actions
597
+ [downloads-image]: http://img.shields.io/npm/dm/qs.svg
598
+ [downloads-url]: http://npm-stat.com/charts.html?package=qs
package/dist/qs.js CHANGED
@@ -45,7 +45,6 @@ module.exports = {
45
45
  var utils = require('./utils');
46
46
 
47
47
  var has = Object.prototype.hasOwnProperty;
48
- var isArray = Array.isArray;
49
48
 
50
49
  var defaults = {
51
50
  allowDots: false,
@@ -71,25 +70,6 @@ var interpretNumericEntities = function (str) {
71
70
  });
72
71
  };
73
72
 
74
- var parseArrayValue = function (val, options) {
75
- if (val && typeof val === 'string' && options.comma && val.indexOf(',') > -1) {
76
- return val.split(',');
77
- }
78
-
79
- return val;
80
- };
81
-
82
- var maybeMap = function maybeMap(val, fn) {
83
- if (isArray(val)) {
84
- var mapped = [];
85
- for (var i = 0; i < val.length; i += 1) {
86
- mapped.push(fn(val[i]));
87
- }
88
- return mapped;
89
- }
90
- return fn(val);
91
- };
92
-
93
73
  // This is what browsers will submit when the ✓ character occurs in an
94
74
  // application/x-www-form-urlencoded body and the encoding of the page containing
95
75
  // the form is iso-8859-1, or when the submitted form has an accept-charset
@@ -134,24 +114,19 @@ var parseValues = function parseQueryStringValues(str, options) {
134
114
 
135
115
  var key, val;
136
116
  if (pos === -1) {
137
- key = options.decoder(part, defaults.decoder, charset);
117
+ key = options.decoder(part, defaults.decoder, charset, 'key');
138
118
  val = options.strictNullHandling ? null : '';
139
119
  } else {
140
- key = options.decoder(part.slice(0, pos), defaults.decoder, charset);
141
- val = maybeMap(
142
- parseArrayValue(part.slice(pos + 1), options),
143
- function (encodedVal) {
144
- return options.decoder(encodedVal, defaults.decoder, charset);
145
- }
146
- );
120
+ key = options.decoder(part.slice(0, pos), defaults.decoder, charset, 'key');
121
+ val = options.decoder(part.slice(pos + 1), defaults.decoder, charset, 'value');
147
122
  }
148
123
 
149
124
  if (val && options.interpretNumericEntities && charset === 'iso-8859-1') {
150
125
  val = interpretNumericEntities(val);
151
126
  }
152
127
 
153
- if (part.indexOf('[]=') > -1) {
154
- val = isArray(val) ? [val] : val;
128
+ if (val && options.comma && val.indexOf(',') > -1) {
129
+ val = val.split(',');
155
130
  }
156
131
 
157
132
  if (has.call(obj, key)) {
@@ -164,8 +139,8 @@ var parseValues = function parseQueryStringValues(str, options) {
164
139
  return obj;
165
140
  };
166
141
 
167
- var parseObject = function (chain, val, options, valuesParsed) {
168
- var leaf = valuesParsed ? val : parseArrayValue(val, options);
142
+ var parseObject = function (chain, val, options) {
143
+ var leaf = val;
169
144
 
170
145
  for (var i = chain.length - 1; i >= 0; --i) {
171
146
  var obj;
@@ -188,7 +163,7 @@ var parseObject = function (chain, val, options, valuesParsed) {
188
163
  ) {
189
164
  obj = [];
190
165
  obj[index] = leaf;
191
- } else if (cleanRoot !== '__proto__') {
166
+ } else {
192
167
  obj[cleanRoot] = leaf;
193
168
  }
194
169
  }
@@ -199,7 +174,7 @@ var parseObject = function (chain, val, options, valuesParsed) {
199
174
  return leaf;
200
175
  };
201
176
 
202
- var parseKeys = function parseQueryStringKeys(givenKey, val, options, valuesParsed) {
177
+ var parseKeys = function parseQueryStringKeys(givenKey, val, options) {
203
178
  if (!givenKey) {
204
179
  return;
205
180
  }
@@ -250,7 +225,7 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options, valuesPars
250
225
  keys.push('[' + key.slice(segment.index) + ']');
251
226
  }
252
227
 
253
- return parseObject(keys, val, options, valuesParsed);
228
+ return parseObject(keys, val, options);
254
229
  };
255
230
 
256
231
  var normalizeParseOptions = function normalizeParseOptions(opts) {
@@ -263,7 +238,7 @@ var normalizeParseOptions = function normalizeParseOptions(opts) {
263
238
  }
264
239
 
265
240
  if (typeof opts.charset !== 'undefined' && opts.charset !== 'utf-8' && opts.charset !== 'iso-8859-1') {
266
- throw new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined');
241
+ throw new Error('The charset option must be either utf-8, iso-8859-1, or undefined');
267
242
  }
268
243
  var charset = typeof opts.charset === 'undefined' ? defaults.charset : opts.charset;
269
244
 
@@ -302,7 +277,7 @@ module.exports = function (str, opts) {
302
277
  var keys = Object.keys(tempObj);
303
278
  for (var i = 0; i < keys.length; ++i) {
304
279
  var key = keys[i];
305
- var newObj = parseKeys(key, tempObj[key], options, typeof str === 'string');
280
+ var newObj = parseKeys(key, tempObj[key], options);
306
281
  obj = utils.merge(obj, newObj, options);
307
282
  }
308
283
 
@@ -330,7 +305,6 @@ var arrayPrefixGenerators = {
330
305
  };
331
306
 
332
307
  var isArray = Array.isArray;
333
- var split = String.prototype.split;
334
308
  var push = Array.prototype.push;
335
309
  var pushToArray = function (arr, valueOrArray) {
336
310
  push.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]);
@@ -393,7 +367,7 @@ var stringify = function stringify(
393
367
 
394
368
  if (obj === null) {
395
369
  if (strictNullHandling) {
396
- return encoder && !encodeValuesOnly ? encoder(prefix, defaults.encoder, charset) : prefix;
370
+ return encoder && !encodeValuesOnly ? encoder(prefix, defaults.encoder, charset, 'key') : prefix;
397
371
  }
398
372
 
399
373
  obj = '';
@@ -401,16 +375,8 @@ var stringify = function stringify(
401
375
 
402
376
  if (isNonNullishPrimitive(obj) || utils.isBuffer(obj)) {
403
377
  if (encoder) {
404
- var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset);
405
- if (generateArrayPrefix === 'comma' && encodeValuesOnly) {
406
- var valuesArray = split.call(String(obj), ',');
407
- var valuesJoined = '';
408
- for (var i = 0; i < valuesArray.length; ++i) {
409
- valuesJoined += (i === 0 ? '' : ',') + formatter(encoder(valuesArray[i], defaults.encoder, charset));
410
- }
411
- return [formatter(keyValue) + '=' + valuesJoined];
412
- }
413
- 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'))];
414
380
  }
415
381
  return [formatter(prefix) + '=' + formatter(String(obj))];
416
382
  }
@@ -429,33 +395,46 @@ var stringify = function stringify(
429
395
  objKeys = sort ? keys.sort(sort) : keys;
430
396
  }
431
397
 
432
- for (var j = 0; j < objKeys.length; ++j) {
433
- var key = objKeys[j];
434
- var value = typeof key === 'object' && typeof key.value !== 'undefined' ? key.value : obj[key];
398
+ for (var i = 0; i < objKeys.length; ++i) {
399
+ var key = objKeys[i];
435
400
 
436
- if (skipNulls && value === null) {
401
+ if (skipNulls && obj[key] === null) {
437
402
  continue;
438
403
  }
439
404
 
440
- var keyPrefix = isArray(obj)
441
- ? typeof generateArrayPrefix === 'function' ? generateArrayPrefix(prefix, key) : prefix
442
- : prefix + (allowDots ? '.' + key : '[' + key + ']');
443
-
444
- pushToArray(values, stringify(
445
- value,
446
- keyPrefix,
447
- generateArrayPrefix,
448
- strictNullHandling,
449
- skipNulls,
450
- encoder,
451
- filter,
452
- sort,
453
- allowDots,
454
- serializeDate,
455
- formatter,
456
- encodeValuesOnly,
457
- charset
458
- ));
405
+ if (isArray(obj)) {
406
+ pushToArray(values, stringify(
407
+ obj[key],
408
+ typeof generateArrayPrefix === 'function' ? generateArrayPrefix(prefix, key) : prefix,
409
+ generateArrayPrefix,
410
+ strictNullHandling,
411
+ skipNulls,
412
+ encoder,
413
+ filter,
414
+ sort,
415
+ allowDots,
416
+ serializeDate,
417
+ formatter,
418
+ encodeValuesOnly,
419
+ charset
420
+ ));
421
+ } else {
422
+ pushToArray(values, stringify(
423
+ obj[key],
424
+ prefix + (allowDots ? '.' + key : '[' + key + ']'),
425
+ generateArrayPrefix,
426
+ strictNullHandling,
427
+ skipNulls,
428
+ encoder,
429
+ filter,
430
+ sort,
431
+ allowDots,
432
+ serializeDate,
433
+ formatter,
434
+ encodeValuesOnly,
435
+ charset
436
+ ));
437
+ }
459
438
  }
460
439
 
461
440
  return values;
@@ -466,7 +445,7 @@ var normalizeStringifyOptions = function normalizeStringifyOptions(opts) {
466
445
  return defaults;
467
446
  }
468
447
 
469
- if (opts.encoder !== null && typeof opts.encoder !== 'undefined' && typeof opts.encoder !== 'function') {
448
+ if (opts.encoder !== null && opts.encoder !== undefined && typeof opts.encoder !== 'function') {
470
449
  throw new TypeError('Encoder has to be a function.');
471
450
  }
472
451
 
@@ -641,7 +620,7 @@ var merge = function merge(target, source, options) {
641
620
  target.push(source);
642
621
  } else if (target && typeof target === 'object') {
643
622
  if ((options && (options.plainObjects || options.allowPrototypes)) || !has.call(Object.prototype, source)) {
644
- target[source] = true; // eslint-disable-line no-param-reassign
623
+ target[source] = true;
645
624
  }
646
625
  } else {
647
626
  return [target, source];
@@ -664,12 +643,12 @@ var merge = function merge(target, source, options) {
664
643
  if (has.call(target, i)) {
665
644
  var targetItem = target[i];
666
645
  if (targetItem && typeof targetItem === 'object' && item && typeof item === 'object') {
667
- target[i] = merge(targetItem, item, options); // eslint-disable-line no-param-reassign
646
+ target[i] = merge(targetItem, item, options);
668
647
  } else {
669
648
  target.push(item);
670
649
  }
671
650
  } else {
672
- target[i] = item; // eslint-disable-line no-param-reassign
651
+ target[i] = item;
673
652
  }
674
653
  });
675
654
  return target;
@@ -679,9 +658,9 @@ var merge = function merge(target, source, options) {
679
658
  var value = source[key];
680
659
 
681
660
  if (has.call(acc, key)) {
682
- acc[key] = merge(acc[key], value, options); // eslint-disable-line no-param-reassign
661
+ acc[key] = merge(acc[key], value, options);
683
662
  } else {
684
- acc[key] = value; // eslint-disable-line no-param-reassign
663
+ acc[key] = value;
685
664
  }
686
665
  return acc;
687
666
  }, mergeTarget);
@@ -689,7 +668,7 @@ var merge = function merge(target, source, options) {
689
668
 
690
669
  var assign = function assignSingleSource(target, source) {
691
670
  return Object.keys(source).reduce(function (acc, key) {
692
- acc[key] = source[key]; // eslint-disable-line no-param-reassign
671
+ acc[key] = source[key];
693
672
  return acc;
694
673
  }, target);
695
674
  };
@@ -762,7 +741,6 @@ var encode = function encode(str, defaultEncoder, charset) {
762
741
 
763
742
  i += 1;
764
743
  c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF));
765
- /* eslint operator-linebreak: [2, "before"] */
766
744
  out += hexTable[0xF0 | (c >> 18)]
767
745
  + hexTable[0x80 | ((c >> 12) & 0x3F)]
768
746
  + hexTable[0x80 | ((c >> 6) & 0x3F)]
package/lib/parse.js CHANGED
@@ -3,7 +3,6 @@
3
3
  var utils = require('./utils');
4
4
 
5
5
  var has = Object.prototype.hasOwnProperty;
6
- var isArray = Array.isArray;
7
6
 
8
7
  var defaults = {
9
8
  allowDots: false,
@@ -29,25 +28,6 @@ var interpretNumericEntities = function (str) {
29
28
  });
30
29
  };
31
30
 
32
- var parseArrayValue = function (val, options) {
33
- if (val && typeof val === 'string' && options.comma && val.indexOf(',') > -1) {
34
- return val.split(',');
35
- }
36
-
37
- return val;
38
- };
39
-
40
- var maybeMap = function maybeMap(val, fn) {
41
- if (isArray(val)) {
42
- var mapped = [];
43
- for (var i = 0; i < val.length; i += 1) {
44
- mapped.push(fn(val[i]));
45
- }
46
- return mapped;
47
- }
48
- return fn(val);
49
- };
50
-
51
31
  // This is what browsers will submit when the ✓ character occurs in an
52
32
  // application/x-www-form-urlencoded body and the encoding of the page containing
53
33
  // the form is iso-8859-1, or when the submitted form has an accept-charset
@@ -92,24 +72,19 @@ var parseValues = function parseQueryStringValues(str, options) {
92
72
 
93
73
  var key, val;
94
74
  if (pos === -1) {
95
- key = options.decoder(part, defaults.decoder, charset);
75
+ key = options.decoder(part, defaults.decoder, charset, 'key');
96
76
  val = options.strictNullHandling ? null : '';
97
77
  } else {
98
- key = options.decoder(part.slice(0, pos), defaults.decoder, charset);
99
- val = maybeMap(
100
- parseArrayValue(part.slice(pos + 1), options),
101
- function (encodedVal) {
102
- return options.decoder(encodedVal, defaults.decoder, charset);
103
- }
104
- );
78
+ key = options.decoder(part.slice(0, pos), defaults.decoder, charset, 'key');
79
+ val = options.decoder(part.slice(pos + 1), defaults.decoder, charset, 'value');
105
80
  }
106
81
 
107
82
  if (val && options.interpretNumericEntities && charset === 'iso-8859-1') {
108
83
  val = interpretNumericEntities(val);
109
84
  }
110
85
 
111
- if (part.indexOf('[]=') > -1) {
112
- val = isArray(val) ? [val] : val;
86
+ if (val && options.comma && val.indexOf(',') > -1) {
87
+ val = val.split(',');
113
88
  }
114
89
 
115
90
  if (has.call(obj, key)) {
@@ -122,8 +97,8 @@ var parseValues = function parseQueryStringValues(str, options) {
122
97
  return obj;
123
98
  };
124
99
 
125
- var parseObject = function (chain, val, options, valuesParsed) {
126
- var leaf = valuesParsed ? val : parseArrayValue(val, options);
100
+ var parseObject = function (chain, val, options) {
101
+ var leaf = val;
127
102
 
128
103
  for (var i = chain.length - 1; i >= 0; --i) {
129
104
  var obj;
@@ -146,7 +121,7 @@ var parseObject = function (chain, val, options, valuesParsed) {
146
121
  ) {
147
122
  obj = [];
148
123
  obj[index] = leaf;
149
- } else if (cleanRoot !== '__proto__') {
124
+ } else {
150
125
  obj[cleanRoot] = leaf;
151
126
  }
152
127
  }
@@ -157,7 +132,7 @@ var parseObject = function (chain, val, options, valuesParsed) {
157
132
  return leaf;
158
133
  };
159
134
 
160
- var parseKeys = function parseQueryStringKeys(givenKey, val, options, valuesParsed) {
135
+ var parseKeys = function parseQueryStringKeys(givenKey, val, options) {
161
136
  if (!givenKey) {
162
137
  return;
163
138
  }
@@ -208,7 +183,7 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options, valuesPars
208
183
  keys.push('[' + key.slice(segment.index) + ']');
209
184
  }
210
185
 
211
- return parseObject(keys, val, options, valuesParsed);
186
+ return parseObject(keys, val, options);
212
187
  };
213
188
 
214
189
  var normalizeParseOptions = function normalizeParseOptions(opts) {
@@ -221,7 +196,7 @@ var normalizeParseOptions = function normalizeParseOptions(opts) {
221
196
  }
222
197
 
223
198
  if (typeof opts.charset !== 'undefined' && opts.charset !== 'utf-8' && opts.charset !== 'iso-8859-1') {
224
- throw new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined');
199
+ throw new Error('The charset option must be either utf-8, iso-8859-1, or undefined');
225
200
  }
226
201
  var charset = typeof opts.charset === 'undefined' ? defaults.charset : opts.charset;
227
202
 
@@ -260,7 +235,7 @@ module.exports = function (str, opts) {
260
235
  var keys = Object.keys(tempObj);
261
236
  for (var i = 0; i < keys.length; ++i) {
262
237
  var key = keys[i];
263
- var newObj = parseKeys(key, tempObj[key], options, typeof str === 'string');
238
+ var newObj = parseKeys(key, tempObj[key], options);
264
239
  obj = utils.merge(obj, newObj, options);
265
240
  }
266
241
 
package/lib/stringify.js CHANGED
@@ -18,7 +18,6 @@ var arrayPrefixGenerators = {
18
18
  };
19
19
 
20
20
  var isArray = Array.isArray;
21
- var split = String.prototype.split;
22
21
  var push = Array.prototype.push;
23
22
  var pushToArray = function (arr, valueOrArray) {
24
23
  push.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]);
@@ -81,7 +80,7 @@ var stringify = function stringify(
81
80
 
82
81
  if (obj === null) {
83
82
  if (strictNullHandling) {
84
- return encoder && !encodeValuesOnly ? encoder(prefix, defaults.encoder, charset) : prefix;
83
+ return encoder && !encodeValuesOnly ? encoder(prefix, defaults.encoder, charset, 'key') : prefix;
85
84
  }
86
85
 
87
86
  obj = '';
@@ -89,16 +88,8 @@ var stringify = function stringify(
89
88
 
90
89
  if (isNonNullishPrimitive(obj) || utils.isBuffer(obj)) {
91
90
  if (encoder) {
92
- var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset);
93
- if (generateArrayPrefix === 'comma' && encodeValuesOnly) {
94
- var valuesArray = split.call(String(obj), ',');
95
- var valuesJoined = '';
96
- for (var i = 0; i < valuesArray.length; ++i) {
97
- valuesJoined += (i === 0 ? '' : ',') + formatter(encoder(valuesArray[i], defaults.encoder, charset));
98
- }
99
- return [formatter(keyValue) + '=' + valuesJoined];
100
- }
101
- 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'))];
102
93
  }
103
94
  return [formatter(prefix) + '=' + formatter(String(obj))];
104
95
  }
@@ -117,33 +108,46 @@ var stringify = function stringify(
117
108
  objKeys = sort ? keys.sort(sort) : keys;
118
109
  }
119
110
 
120
- for (var j = 0; j < objKeys.length; ++j) {
121
- var key = objKeys[j];
122
- var value = typeof key === 'object' && typeof key.value !== 'undefined' ? key.value : obj[key];
111
+ for (var i = 0; i < objKeys.length; ++i) {
112
+ var key = objKeys[i];
123
113
 
124
- if (skipNulls && value === null) {
114
+ if (skipNulls && obj[key] === null) {
125
115
  continue;
126
116
  }
127
117
 
128
- var keyPrefix = isArray(obj)
129
- ? typeof generateArrayPrefix === 'function' ? generateArrayPrefix(prefix, key) : prefix
130
- : prefix + (allowDots ? '.' + key : '[' + key + ']');
131
-
132
- pushToArray(values, stringify(
133
- value,
134
- keyPrefix,
135
- generateArrayPrefix,
136
- strictNullHandling,
137
- skipNulls,
138
- encoder,
139
- filter,
140
- sort,
141
- allowDots,
142
- serializeDate,
143
- formatter,
144
- encodeValuesOnly,
145
- charset
146
- ));
118
+ if (isArray(obj)) {
119
+ pushToArray(values, stringify(
120
+ obj[key],
121
+ typeof generateArrayPrefix === 'function' ? generateArrayPrefix(prefix, key) : prefix,
122
+ generateArrayPrefix,
123
+ strictNullHandling,
124
+ skipNulls,
125
+ encoder,
126
+ filter,
127
+ sort,
128
+ allowDots,
129
+ serializeDate,
130
+ formatter,
131
+ encodeValuesOnly,
132
+ charset
133
+ ));
134
+ } else {
135
+ pushToArray(values, stringify(
136
+ obj[key],
137
+ prefix + (allowDots ? '.' + key : '[' + key + ']'),
138
+ generateArrayPrefix,
139
+ strictNullHandling,
140
+ skipNulls,
141
+ encoder,
142
+ filter,
143
+ sort,
144
+ allowDots,
145
+ serializeDate,
146
+ formatter,
147
+ encodeValuesOnly,
148
+ charset
149
+ ));
150
+ }
147
151
  }
148
152
 
149
153
  return values;
@@ -154,7 +158,7 @@ var normalizeStringifyOptions = function normalizeStringifyOptions(opts) {
154
158
  return defaults;
155
159
  }
156
160
 
157
- if (opts.encoder !== null && typeof opts.encoder !== 'undefined' && typeof opts.encoder !== 'function') {
161
+ if (opts.encoder !== null && opts.encoder !== undefined && typeof opts.encoder !== 'function') {
158
162
  throw new TypeError('Encoder has to be a function.');
159
163
  }
160
164
 
package/lib/utils.js CHANGED
@@ -52,7 +52,7 @@ var merge = function merge(target, source, options) {
52
52
  target.push(source);
53
53
  } else if (target && typeof target === 'object') {
54
54
  if ((options && (options.plainObjects || options.allowPrototypes)) || !has.call(Object.prototype, source)) {
55
- target[source] = true; // eslint-disable-line no-param-reassign
55
+ target[source] = true;
56
56
  }
57
57
  } else {
58
58
  return [target, source];
@@ -75,12 +75,12 @@ var merge = function merge(target, source, options) {
75
75
  if (has.call(target, i)) {
76
76
  var targetItem = target[i];
77
77
  if (targetItem && typeof targetItem === 'object' && item && typeof item === 'object') {
78
- target[i] = merge(targetItem, item, options); // eslint-disable-line no-param-reassign
78
+ target[i] = merge(targetItem, item, options);
79
79
  } else {
80
80
  target.push(item);
81
81
  }
82
82
  } else {
83
- target[i] = item; // eslint-disable-line no-param-reassign
83
+ target[i] = item;
84
84
  }
85
85
  });
86
86
  return target;
@@ -90,9 +90,9 @@ var merge = function merge(target, source, options) {
90
90
  var value = source[key];
91
91
 
92
92
  if (has.call(acc, key)) {
93
- acc[key] = merge(acc[key], value, options); // eslint-disable-line no-param-reassign
93
+ acc[key] = merge(acc[key], value, options);
94
94
  } else {
95
- acc[key] = value; // eslint-disable-line no-param-reassign
95
+ acc[key] = value;
96
96
  }
97
97
  return acc;
98
98
  }, mergeTarget);
@@ -100,7 +100,7 @@ var merge = function merge(target, source, options) {
100
100
 
101
101
  var assign = function assignSingleSource(target, source) {
102
102
  return Object.keys(source).reduce(function (acc, key) {
103
- acc[key] = source[key]; // eslint-disable-line no-param-reassign
103
+ acc[key] = source[key];
104
104
  return acc;
105
105
  }, target);
106
106
  };
@@ -173,7 +173,6 @@ var encode = function encode(str, defaultEncoder, charset) {
173
173
 
174
174
  i += 1;
175
175
  c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF));
176
- /* eslint operator-linebreak: [2, "before"] */
177
176
  out += hexTable[0xF0 | (c >> 18)]
178
177
  + hexTable[0x80 | ((c >> 12) & 0x3F)]
179
178
  + hexTable[0x80 | ((c >> 6) & 0x3F)]
package/package.json CHANGED
@@ -2,14 +2,11 @@
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.3",
5
+ "version": "6.9.0",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "https://github.com/ljharb/qs.git"
9
9
  },
10
- "funding": {
11
- "url": "https://github.com/sponsors/ljharb"
12
- },
13
10
  "main": "lib/index.js",
14
11
  "contributors": [
15
12
  {
@@ -29,34 +26,33 @@
29
26
  "engines": {
30
27
  "node": ">=0.6"
31
28
  },
29
+ "dependencies": {},
32
30
  "devDependencies": {
33
- "@ljharb/eslint-config": "^20.1.0",
34
- "browserify": "^16.5.2",
31
+ "@ljharb/eslint-config": "^14.1.0",
32
+ "browserify": "^16.5.0",
35
33
  "covert": "^1.1.1",
36
34
  "eclint": "^2.8.1",
37
- "eslint": "^8.6.0",
35
+ "eslint": "^6.4.0",
38
36
  "evalmd": "^0.0.19",
39
37
  "for-each": "^0.3.3",
40
- "has-symbols": "^1.0.2",
41
- "iconv-lite": "^0.5.1",
42
- "in-publish": "^2.0.1",
43
- "mkdirp": "^0.5.4",
44
- "object-inspect": "^1.12.0",
38
+ "has-symbols": "^1.0.0",
39
+ "iconv-lite": "^0.4.24",
40
+ "mkdirp": "^0.5.1",
41
+ "object-inspect": "^1.6.0",
45
42
  "qs-iconv": "^1.0.4",
46
- "safe-publish-latest": "^2.0.0",
43
+ "safe-publish-latest": "^1.1.3",
47
44
  "safer-buffer": "^2.1.2",
48
- "tape": "^5.4.0"
45
+ "tape": "^4.11.0"
49
46
  },
50
47
  "scripts": {
51
- "prepublishOnly": "safe-publish-latest && npm run dist",
52
- "prepublish": "not-in-publish || npm run prepublishOnly",
48
+ "prepublish": "safe-publish-latest && npm run dist",
53
49
  "pretest": "npm run --silent readme && npm run --silent lint",
54
50
  "test": "npm run --silent coverage",
55
51
  "tests-only": "node test",
56
- "posttest": "npx aud --production",
52
+ "posttest": "npx aud",
57
53
  "readme": "evalmd README.md",
58
- "postlint": "eclint check * lib/* test/* !dist/* '!coverage/**' '.nyc_output/**'",
59
- "lint": "eslint .",
54
+ "postlint": "eclint check * lib/* test/*",
55
+ "lint": "eslint lib/*.js test/*.js",
60
56
  "coverage": "covert test",
61
57
  "dist": "mkdirp dist && browserify --standalone Qs lib/index.js > dist/qs.js"
62
58
  },
package/test/.eslintrc ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "rules": {
3
+ "array-bracket-newline": 0,
4
+ "array-element-newline": 0,
5
+ "consistent-return": 2,
6
+ "function-paren-newline": 0,
7
+ "max-lines": 0,
8
+ "max-lines-per-function": 0,
9
+ "max-nested-callbacks": [2, 3],
10
+ "max-statements": 0,
11
+ "no-buffer-constructor": 0,
12
+ "no-extend-native": 0,
13
+ "no-magic-numbers": 0,
14
+ "no-throw-literal": 0,
15
+ "object-curly-newline": 0,
16
+ "sort-keys": 0,
17
+ }
18
+ }
package/test/parse.js CHANGED
@@ -400,43 +400,6 @@ test('parse()', function (t) {
400
400
  st.end();
401
401
  });
402
402
 
403
- t.test('parses values with comma as array divider', function (st) {
404
- st.deepEqual(qs.parse({ foo: 'bar,tee' }, { comma: false }), { foo: 'bar,tee' });
405
- st.deepEqual(qs.parse({ foo: 'bar,tee' }, { comma: true }), { foo: ['bar', 'tee'] });
406
- st.end();
407
- });
408
-
409
- t.test('use number decoder, parses string that has one number with comma option enabled', function (st) {
410
- var decoder = function (str, defaultDecoder, charset, type) {
411
- if (!isNaN(Number(str))) {
412
- return parseFloat(str);
413
- }
414
- return defaultDecoder(str, defaultDecoder, charset, type);
415
- };
416
-
417
- st.deepEqual(qs.parse('foo=1', { comma: true, decoder: decoder }), { foo: 1 });
418
- st.deepEqual(qs.parse('foo=0', { comma: true, decoder: decoder }), { foo: 0 });
419
-
420
- st.end();
421
- });
422
-
423
- t.test('parses brackets holds array of arrays when having two parts of strings with comma as array divider', function (st) {
424
- st.deepEqual(qs.parse('foo[]=1,2,3&foo[]=4,5,6', { comma: true }), { foo: [['1', '2', '3'], ['4', '5', '6']] });
425
- st.deepEqual(qs.parse('foo[]=1,2,3&foo[]=', { comma: true }), { foo: [['1', '2', '3'], ''] });
426
- st.deepEqual(qs.parse('foo[]=1,2,3&foo[]=,', { comma: true }), { foo: [['1', '2', '3'], ['', '']] });
427
- st.deepEqual(qs.parse('foo[]=1,2,3&foo[]=a', { comma: true }), { foo: [['1', '2', '3'], 'a'] });
428
-
429
- st.end();
430
- });
431
-
432
- t.test('parses comma delimited array while having percent-encoded comma treated as normal text', function (st) {
433
- st.deepEqual(qs.parse('foo=a%2Cb', { comma: true }), { foo: 'a,b' });
434
- st.deepEqual(qs.parse('foo=a%2C%20b,d', { comma: true }), { foo: ['a, b', 'd'] });
435
- st.deepEqual(qs.parse('foo=a%2C%20b,c%2C%20d', { comma: true }), { foo: ['a, b', 'c, d'] });
436
-
437
- st.end();
438
- });
439
-
440
403
  t.test('parses an object in dot notation', function (st) {
441
404
  var input = {
442
405
  'user.name': { 'pop[bob]': 3 },
@@ -613,73 +576,13 @@ test('parse()', function (t) {
613
576
 
614
577
  st.deepEqual(
615
578
  qs.parse('a[b]=c&a=toString', { plainObjects: true }),
616
- { __proto__: null, a: { __proto__: null, b: 'c', toString: true } },
579
+ { a: { b: 'c', toString: true } },
617
580
  'can overwrite prototype with plainObjects true'
618
581
  );
619
582
 
620
583
  st.end();
621
584
  });
622
585
 
623
- t.test('dunder proto is ignored', function (st) {
624
- var payload = 'categories[__proto__]=login&categories[__proto__]&categories[length]=42';
625
- var result = qs.parse(payload, { allowPrototypes: true });
626
-
627
- st.deepEqual(
628
- result,
629
- {
630
- categories: {
631
- length: '42'
632
- }
633
- },
634
- 'silent [[Prototype]] payload'
635
- );
636
-
637
- var plainResult = qs.parse(payload, { allowPrototypes: true, plainObjects: true });
638
-
639
- st.deepEqual(
640
- plainResult,
641
- {
642
- __proto__: null,
643
- categories: {
644
- __proto__: null,
645
- length: '42'
646
- }
647
- },
648
- 'silent [[Prototype]] payload: plain objects'
649
- );
650
-
651
- var query = qs.parse('categories[__proto__]=cats&categories[__proto__]=dogs&categories[some][json]=toInject', { allowPrototypes: true });
652
-
653
- st.notOk(Array.isArray(query.categories), 'is not an array');
654
- st.notOk(query.categories instanceof Array, 'is not instanceof an array');
655
- st.deepEqual(query.categories, { some: { json: 'toInject' } });
656
- st.equal(JSON.stringify(query.categories), '{"some":{"json":"toInject"}}', 'stringifies as a non-array');
657
-
658
- st.deepEqual(
659
- qs.parse('foo[__proto__][hidden]=value&foo[bar]=stuffs', { allowPrototypes: true }),
660
- {
661
- foo: {
662
- bar: 'stuffs'
663
- }
664
- },
665
- 'hidden values'
666
- );
667
-
668
- st.deepEqual(
669
- qs.parse('foo[__proto__][hidden]=value&foo[bar]=stuffs', { allowPrototypes: true, plainObjects: true }),
670
- {
671
- __proto__: null,
672
- foo: {
673
- __proto__: null,
674
- bar: 'stuffs'
675
- }
676
- },
677
- 'hidden values: plain objects'
678
- );
679
-
680
- st.end();
681
- });
682
-
683
586
  t.test('can return null objects', { skip: !Object.create }, function (st) {
684
587
  var expected = Object.create(null);
685
588
  expected.a = Object.create(null);
@@ -813,5 +716,20 @@ test('parse()', function (t) {
813
716
  st.end();
814
717
  });
815
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
+
816
734
  t.end();
817
735
  });
package/test/stringify.js CHANGED
@@ -132,10 +132,10 @@ test('stringify()', function (t) {
132
132
  });
133
133
 
134
134
  t.test('stringifies a nested array value', function (st) {
135
- st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true, arrayFormat: 'indices' }), 'a[b][0]=c&a[b][1]=d');
136
- st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a[b][]=c&a[b][]=d');
137
- st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true, arrayFormat: 'comma' }), 'a[b]=c,d');
138
- st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true }), 'a[b][0]=c&a[b][1]=d');
135
+ st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { arrayFormat: 'indices' }), 'a%5Bb%5D%5B0%5D=c&a%5Bb%5D%5B1%5D=d');
136
+ st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { arrayFormat: 'brackets' }), 'a%5Bb%5D%5B%5D=c&a%5Bb%5D%5B%5D=d');
137
+ st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { arrayFormat: 'comma' }), 'a%5Bb%5D=c%2Cd'); // a[b]=c,d
138
+ st.equal(qs.stringify({ a: { b: ['c', 'd'] } }), 'a%5Bb%5D%5B0%5D=c&a%5Bb%5D%5B1%5D=d');
139
139
  st.end();
140
140
  });
141
141
 
@@ -143,7 +143,7 @@ test('stringify()', function (t) {
143
143
  st.equal(
144
144
  qs.stringify(
145
145
  { a: { b: ['c', 'd'] } },
146
- { allowDots: true, encodeValuesOnly: true, arrayFormat: 'indices' }
146
+ { allowDots: true, encode: false, arrayFormat: 'indices' }
147
147
  ),
148
148
  'a.b[0]=c&a.b[1]=d',
149
149
  'indices: stringifies with dots + indices'
@@ -151,7 +151,7 @@ test('stringify()', function (t) {
151
151
  st.equal(
152
152
  qs.stringify(
153
153
  { a: { b: ['c', 'd'] } },
154
- { allowDots: true, encodeValuesOnly: true, arrayFormat: 'brackets' }
154
+ { allowDots: true, encode: false, arrayFormat: 'brackets' }
155
155
  ),
156
156
  'a.b[]=c&a.b[]=d',
157
157
  'brackets: stringifies with dots + brackets'
@@ -159,7 +159,7 @@ test('stringify()', function (t) {
159
159
  st.equal(
160
160
  qs.stringify(
161
161
  { a: { b: ['c', 'd'] } },
162
- { allowDots: true, encodeValuesOnly: true, arrayFormat: 'comma' }
162
+ { allowDots: true, encode: false, arrayFormat: 'comma' }
163
163
  ),
164
164
  'a.b=c,d',
165
165
  'comma: stringifies with dots + comma'
@@ -167,7 +167,7 @@ test('stringify()', function (t) {
167
167
  st.equal(
168
168
  qs.stringify(
169
169
  { a: { b: ['c', 'd'] } },
170
- { allowDots: true, encodeValuesOnly: true }
170
+ { allowDots: true, encode: false }
171
171
  ),
172
172
  'a.b[0]=c&a.b[1]=d',
173
173
  'default: stringifies with dots + indices'
@@ -215,23 +215,17 @@ test('stringify()', function (t) {
215
215
 
216
216
  t.test('stringifies an array with mixed objects and primitives', function (st) {
217
217
  st.equal(
218
- qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'indices' }),
218
+ qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encode: false, arrayFormat: 'indices' }),
219
219
  'a[0][b]=1&a[1]=2&a[2]=3',
220
220
  'indices => indices'
221
221
  );
222
222
  st.equal(
223
- qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
223
+ qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encode: false, arrayFormat: 'brackets' }),
224
224
  'a[][b]=1&a[]=2&a[]=3',
225
225
  'brackets => brackets'
226
226
  );
227
227
  st.equal(
228
- qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'comma' }),
229
- '???',
230
- 'brackets => brackets',
231
- { skip: 'TODO: figure out what this should do' }
232
- );
233
- st.equal(
234
- qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true }),
228
+ qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encode: false }),
235
229
  'a[0][b]=1&a[1]=2&a[2]=3',
236
230
  'default => indices'
237
231
  );
@@ -725,5 +719,20 @@ test('stringify()', function (t) {
725
719
  st.end();
726
720
  });
727
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
+
728
737
  t.end();
729
738
  });
package/.travis.yml DELETED
@@ -1,12 +0,0 @@
1
- version: ~> 1.0
2
- language: node_js
3
- os:
4
- - linux
5
- import:
6
- - ljharb/travis-ci:node/all.yml
7
- - ljharb/travis-ci:node/pretest.yml
8
- - ljharb/travis-ci:node/posttest.yml
9
- - ljharb/travis-ci:node/coverage.yml
10
- matrix:
11
- allow_failures:
12
- - env: COVERAGE=true # temporarily allow this to fail