qs 6.7.3 → 6.8.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
@@ -32,6 +31,3 @@ indent_size = 2
32
31
  [LICENSE]
33
32
  indent_size = 2
34
33
  max_line_length = off
35
-
36
- [.nycrc]
37
- indent_style = tab
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
- "max-lines-per-function": 0,
30
- "max-statements": 0,
31
- "no-extend-native": 0,
32
- "function-paren-newline": 0,
33
- },
34
- },
35
- ],
19
+ "operator-linebreak": [2, "before"],
20
+ }
36
21
  }
package/CHANGELOG.md CHANGED
@@ -1,39 +1,16 @@
1
- ## **6.7.3**
2
- - [Fix] `parse`: ignore `__proto__` keys (#428)
3
- - [Fix] `stringify`: avoid encoding arrayformat comma when `encodeValuesOnly = true` (#424)
4
- - [Robustness] `stringify`: avoid relying on a global `undefined` (#427)
5
- - [readme] remove travis badge; add github actions/codecov badges; update URLs
6
- - [Docs] add note and links for coercing primitive values (#408)
7
- - [meta] fix README.md (#399)
8
- - [meta] do not publish workflow files
9
- - [actions] backport actions from main
10
- - [Dev Deps] backport updates from main
11
- - [Tests] use `nyc` for coverage
12
- - [Tests] clean up stringify tests slightly
13
-
14
- ## **6.7.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.7.1**
19
- - [Fix] `parse`: Fix parsing array from object with `comma` true (#359)
20
- - [Fix] `parse`: with comma true, handle field that holds an array of arrays (#335)
21
- - [fix] `parse`: with comma true, do not split non-string values (#334)
22
- - [Fix] `parse`: throw a TypeError instead of an Error for bad charset (#349)
1
+ ## **6.8.0**
2
+ - [New] add `depth=false` to preserve the original key; [Fix] `depth=0` should preserve the original key (#326)
3
+ - [New] [Fix] stringify symbols and bigints
4
+ - [Fix] ensure node 0.12 can stringify Symbols
23
5
  - [Fix] fix for an impossible situation: when the formatter is called with a non-string value
24
6
  - [Refactor] `formats`: tiny bit of cleanup.
25
- - readme: add security note
26
- - [meta] add tidelift marketing copy
27
- - [meta] add `funding` field
7
+ - [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `browserify`, `safe-publish-latest`, `iconv-lite`, `tape`
8
+ - [Tests] add tests for `depth=0` and `depth=false` behavior, both current and intuitive/intended (#326)
9
+ - [Tests] use `eclint` instead of `editorconfig-tools`
10
+ - [docs] readme: add security note
11
+ - [meta] add github sponsorship
28
12
  - [meta] add FUNDING.yml
29
13
  - [meta] Clean up license text so it’s properly detected as BSD-3-Clause
30
- - [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `tape`, `safe-publish-latest`, `evalmd`, `iconv-lite`, `mkdirp`, `object-inspect`, `browserify`
31
- - [Tests] `parse`: add passing `arrayFormat` tests
32
- - [Tests] use shared travis-ci configs
33
- - [Tests] `Buffer.from` in node v5.0-v5.9 and v4.0-v4.4 requires a TypedArray
34
- - [Tests] add tests for `depth=0` and `depth=false` behavior, both current and intuitive/intended
35
- - [Tests] use `eclint` instead of `editorconfig-tools`
36
- - [actions] add automatic rebasing / merge commit blocking
37
14
 
38
15
  ## **6.7.0**
39
16
  - [New] `stringify`/`parse`: add `comma` as an `arrayFormat` option (#276, #219)
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)
@@ -342,30 +330,6 @@ var decoded = qs.parse('x=z', { decoder: function (str) {
342
330
  }})
343
331
  ```
344
332
 
345
- You can encode keys and values using different logic by using the type argument provided to the encoder:
346
-
347
- ```javascript
348
- var encoded = qs.stringify({ a: { b: 'c' } }, { encoder: function (str, defaultEncoder, charset, type) {
349
- if (type === 'key') {
350
- return // Encoded key
351
- } else if (type === 'value') {
352
- return // Encoded value
353
- }
354
- }})
355
- ```
356
-
357
- The type argument is also provided to the decoder:
358
-
359
- ```javascript
360
- var decoded = qs.parse('x=z', { decoder: function (str, defaultDecoder, charset, type) {
361
- if (type === 'key') {
362
- return // Decoded key
363
- } else if (type === 'value') {
364
- return // Decoded value
365
- }
366
- }})
367
- ```
368
-
369
333
  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.
370
334
 
371
335
  When arrays are stringified, by default they are given explicit indices:
@@ -593,24 +557,18 @@ assert.equal(qs.stringify({ a: 'b c' }, { format : 'RFC1738' }), 'a=b+c');
593
557
 
594
558
  Please email [@ljharb](https://github.com/ljharb) or see https://tidelift.com/security if you have a potential security vulnerability to report.
595
559
 
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
560
+ [1]: https://npmjs.org/package/qs
561
+ [2]: http://versionbadg.es/ljharb/qs.svg
562
+ [3]: https://api.travis-ci.org/ljharb/qs.svg
563
+ [4]: https://travis-ci.org/ljharb/qs
564
+ [5]: https://david-dm.org/ljharb/qs.svg
565
+ [6]: https://david-dm.org/ljharb/qs
566
+ [7]: https://david-dm.org/ljharb/qs/dev-status.svg
567
+ [8]: https://david-dm.org/ljharb/qs?type=dev
568
+ [9]: https://ci.testling.com/ljharb/qs.png
569
+ [10]: https://ci.testling.com/ljharb/qs
570
+ [11]: https://nodei.co/npm/qs.png?downloads=true&stars=true
571
+ [license-image]: http://img.shields.io/npm/l/qs.svg
610
572
  [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
573
+ [downloads-image]: http://img.shields.io/npm/dm/qs.svg
574
+ [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
@@ -138,20 +118,15 @@ var parseValues = function parseQueryStringValues(str, options) {
138
118
  val = options.strictNullHandling ? null : '';
139
119
  } else {
140
120
  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
- );
121
+ val = options.decoder(part.slice(pos + 1), defaults.decoder, charset);
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,18 +163,18 @@ 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
  }
195
170
 
196
- leaf = obj; // eslint-disable-line no-param-reassign
171
+ leaf = obj;
197
172
  }
198
173
 
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
  }
@@ -214,7 +189,7 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options, valuesPars
214
189
 
215
190
  // Get the parent
216
191
 
217
- var segment = brackets.exec(key);
192
+ var segment = options.depth > 0 && brackets.exec(key);
218
193
  var parent = segment ? key.slice(0, segment.index) : key;
219
194
 
220
195
  // Stash the parent if it exists
@@ -234,7 +209,7 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options, valuesPars
234
209
  // Loop through children appending to the array until we hit depth
235
210
 
236
211
  var i = 0;
237
- while ((segment = child.exec(key)) !== null && i < options.depth) {
212
+ while (options.depth > 0 && (segment = child.exec(key)) !== null && i < options.depth) {
238
213
  i += 1;
239
214
  if (!options.plainObjects && has.call(Object.prototype, segment[1].slice(1, -1))) {
240
215
  if (!options.allowPrototypes) {
@@ -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
 
@@ -276,7 +251,8 @@ var normalizeParseOptions = function normalizeParseOptions(opts) {
276
251
  comma: typeof opts.comma === 'boolean' ? opts.comma : defaults.comma,
277
252
  decoder: typeof opts.decoder === 'function' ? opts.decoder : defaults.decoder,
278
253
  delimiter: typeof opts.delimiter === 'string' || utils.isRegExp(opts.delimiter) ? opts.delimiter : defaults.delimiter,
279
- depth: typeof opts.depth === 'number' ? opts.depth : defaults.depth,
254
+ // eslint-disable-next-line no-implicit-coercion, no-extra-parens
255
+ depth: (typeof opts.depth === 'number' || opts.depth === false) ? +opts.depth : defaults.depth,
280
256
  ignoreQueryPrefix: opts.ignoreQueryPrefix === true,
281
257
  interpretNumericEntities: typeof opts.interpretNumericEntities === 'boolean' ? opts.interpretNumericEntities : defaults.interpretNumericEntities,
282
258
  parameterLimit: typeof opts.parameterLimit === 'number' ? opts.parameterLimit : defaults.parameterLimit,
@@ -301,7 +277,7 @@ module.exports = function (str, opts) {
301
277
  var keys = Object.keys(tempObj);
302
278
  for (var i = 0; i < keys.length; ++i) {
303
279
  var key = keys[i];
304
- var newObj = parseKeys(key, tempObj[key], options, typeof str === 'string');
280
+ var newObj = parseKeys(key, tempObj[key], options);
305
281
  obj = utils.merge(obj, newObj, options);
306
282
  }
307
283
 
@@ -316,20 +292,19 @@ var formats = require('./formats');
316
292
  var has = Object.prototype.hasOwnProperty;
317
293
 
318
294
  var arrayPrefixGenerators = {
319
- brackets: function brackets(prefix) {
295
+ brackets: function brackets(prefix) { // eslint-disable-line func-name-matching
320
296
  return prefix + '[]';
321
297
  },
322
298
  comma: 'comma',
323
- indices: function indices(prefix, key) {
299
+ indices: function indices(prefix, key) { // eslint-disable-line func-name-matching
324
300
  return prefix + '[' + key + ']';
325
301
  },
326
- repeat: function repeat(prefix) {
302
+ repeat: function repeat(prefix) { // eslint-disable-line func-name-matching
327
303
  return prefix;
328
304
  }
329
305
  };
330
306
 
331
307
  var isArray = Array.isArray;
332
- var split = String.prototype.split;
333
308
  var push = Array.prototype.push;
334
309
  var pushToArray = function (arr, valueOrArray) {
335
310
  push.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]);
@@ -351,14 +326,22 @@ var defaults = {
351
326
  formatter: formats.formatters[defaultFormat],
352
327
  // deprecated
353
328
  indices: false,
354
- serializeDate: function serializeDate(date) {
329
+ serializeDate: function serializeDate(date) { // eslint-disable-line func-name-matching
355
330
  return toISO.call(date);
356
331
  },
357
332
  skipNulls: false,
358
333
  strictNullHandling: false
359
334
  };
360
335
 
361
- var stringify = function stringify(
336
+ var isNonNullishPrimitive = function isNonNullishPrimitive(v) { // eslint-disable-line func-name-matching
337
+ return typeof v === 'string'
338
+ || typeof v === 'number'
339
+ || typeof v === 'boolean'
340
+ || typeof v === 'symbol'
341
+ || typeof v === 'bigint'; // eslint-disable-line valid-typeof
342
+ };
343
+
344
+ var stringify = function stringify( // eslint-disable-line func-name-matching
362
345
  object,
363
346
  prefix,
364
347
  generateArrayPrefix,
@@ -390,17 +373,9 @@ var stringify = function stringify(
390
373
  obj = '';
391
374
  }
392
375
 
393
- if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean' || utils.isBuffer(obj)) {
376
+ if (isNonNullishPrimitive(obj) || utils.isBuffer(obj)) {
394
377
  if (encoder) {
395
378
  var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset);
396
- if (generateArrayPrefix === 'comma' && encodeValuesOnly) {
397
- var valuesArray = split.call(String(obj), ',');
398
- var valuesJoined = '';
399
- for (var i = 0; i < valuesArray.length; ++i) {
400
- valuesJoined += (i === 0 ? '' : ',') + formatter(encoder(valuesArray[i], defaults.encoder, charset));
401
- }
402
- return [formatter(keyValue) + '=' + valuesJoined];
403
- }
404
379
  return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder, charset))];
405
380
  }
406
381
  return [formatter(prefix) + '=' + formatter(String(obj))];
@@ -420,9 +395,8 @@ var stringify = function stringify(
420
395
  objKeys = sort ? keys.sort(sort) : keys;
421
396
  }
422
397
 
423
- for (var j = 0; j < objKeys.length; ++j) {
424
- var key = objKeys[j];
425
- 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];
426
400
 
427
401
  if (skipNulls && obj[key] === null) {
428
402
  continue;
@@ -430,7 +404,7 @@ var stringify = function stringify(
430
404
 
431
405
  if (isArray(obj)) {
432
406
  pushToArray(values, stringify(
433
- value,
407
+ obj[key],
434
408
  typeof generateArrayPrefix === 'function' ? generateArrayPrefix(prefix, key) : prefix,
435
409
  generateArrayPrefix,
436
410
  strictNullHandling,
@@ -446,7 +420,7 @@ var stringify = function stringify(
446
420
  ));
447
421
  } else {
448
422
  pushToArray(values, stringify(
449
- value,
423
+ obj[key],
450
424
  prefix + (allowDots ? '.' + key : '[' + key + ']'),
451
425
  generateArrayPrefix,
452
426
  strictNullHandling,
@@ -471,7 +445,7 @@ var normalizeStringifyOptions = function normalizeStringifyOptions(opts) {
471
445
  return defaults;
472
446
  }
473
447
 
474
- if (opts.encoder !== null && typeof opts.encoder !== 'undefined' && typeof opts.encoder !== 'function') {
448
+ if (opts.encoder !== null && opts.encoder !== undefined && typeof opts.encoder !== 'function') {
475
449
  throw new TypeError('Encoder has to be a function.');
476
450
  }
477
451
 
@@ -646,7 +620,7 @@ var merge = function merge(target, source, options) {
646
620
  target.push(source);
647
621
  } else if (target && typeof target === 'object') {
648
622
  if ((options && (options.plainObjects || options.allowPrototypes)) || !has.call(Object.prototype, source)) {
649
- target[source] = true; // eslint-disable-line no-param-reassign
623
+ target[source] = true;
650
624
  }
651
625
  } else {
652
626
  return [target, source];
@@ -669,12 +643,12 @@ var merge = function merge(target, source, options) {
669
643
  if (has.call(target, i)) {
670
644
  var targetItem = target[i];
671
645
  if (targetItem && typeof targetItem === 'object' && item && typeof item === 'object') {
672
- target[i] = merge(targetItem, item, options); // eslint-disable-line no-param-reassign
646
+ target[i] = merge(targetItem, item, options);
673
647
  } else {
674
648
  target.push(item);
675
649
  }
676
650
  } else {
677
- target[i] = item; // eslint-disable-line no-param-reassign
651
+ target[i] = item;
678
652
  }
679
653
  });
680
654
  return target;
@@ -684,9 +658,9 @@ var merge = function merge(target, source, options) {
684
658
  var value = source[key];
685
659
 
686
660
  if (has.call(acc, key)) {
687
- acc[key] = merge(acc[key], value, options); // eslint-disable-line no-param-reassign
661
+ acc[key] = merge(acc[key], value, options);
688
662
  } else {
689
- acc[key] = value; // eslint-disable-line no-param-reassign
663
+ acc[key] = value;
690
664
  }
691
665
  return acc;
692
666
  }, mergeTarget);
@@ -694,7 +668,7 @@ var merge = function merge(target, source, options) {
694
668
 
695
669
  var assign = function assignSingleSource(target, source) {
696
670
  return Object.keys(source).reduce(function (acc, key) {
697
- acc[key] = source[key]; // eslint-disable-line no-param-reassign
671
+ acc[key] = source[key];
698
672
  return acc;
699
673
  }, target);
700
674
  };
@@ -720,7 +694,12 @@ var encode = function encode(str, defaultEncoder, charset) {
720
694
  return str;
721
695
  }
722
696
 
723
- var string = typeof str === 'string' ? str : String(str);
697
+ var string = str;
698
+ if (typeof str === 'symbol') {
699
+ string = Symbol.prototype.toString.call(str);
700
+ } else if (typeof str !== 'string') {
701
+ string = String(str);
702
+ }
724
703
 
725
704
  if (charset === 'iso-8859-1') {
726
705
  return escape(string).replace(/%u[0-9a-f]{4}/gi, function ($0) {
@@ -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
@@ -96,20 +76,15 @@ var parseValues = function parseQueryStringValues(str, options) {
96
76
  val = options.strictNullHandling ? null : '';
97
77
  } else {
98
78
  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
- );
79
+ val = options.decoder(part.slice(pos + 1), defaults.decoder, charset);
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,18 +121,18 @@ 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
  }
153
128
 
154
- leaf = obj; // eslint-disable-line no-param-reassign
129
+ leaf = obj;
155
130
  }
156
131
 
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
  }
@@ -172,7 +147,7 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options, valuesPars
172
147
 
173
148
  // Get the parent
174
149
 
175
- var segment = brackets.exec(key);
150
+ var segment = options.depth > 0 && brackets.exec(key);
176
151
  var parent = segment ? key.slice(0, segment.index) : key;
177
152
 
178
153
  // Stash the parent if it exists
@@ -192,7 +167,7 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options, valuesPars
192
167
  // Loop through children appending to the array until we hit depth
193
168
 
194
169
  var i = 0;
195
- while ((segment = child.exec(key)) !== null && i < options.depth) {
170
+ while (options.depth > 0 && (segment = child.exec(key)) !== null && i < options.depth) {
196
171
  i += 1;
197
172
  if (!options.plainObjects && has.call(Object.prototype, segment[1].slice(1, -1))) {
198
173
  if (!options.allowPrototypes) {
@@ -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
 
@@ -234,7 +209,8 @@ var normalizeParseOptions = function normalizeParseOptions(opts) {
234
209
  comma: typeof opts.comma === 'boolean' ? opts.comma : defaults.comma,
235
210
  decoder: typeof opts.decoder === 'function' ? opts.decoder : defaults.decoder,
236
211
  delimiter: typeof opts.delimiter === 'string' || utils.isRegExp(opts.delimiter) ? opts.delimiter : defaults.delimiter,
237
- depth: typeof opts.depth === 'number' ? opts.depth : defaults.depth,
212
+ // eslint-disable-next-line no-implicit-coercion, no-extra-parens
213
+ depth: (typeof opts.depth === 'number' || opts.depth === false) ? +opts.depth : defaults.depth,
238
214
  ignoreQueryPrefix: opts.ignoreQueryPrefix === true,
239
215
  interpretNumericEntities: typeof opts.interpretNumericEntities === 'boolean' ? opts.interpretNumericEntities : defaults.interpretNumericEntities,
240
216
  parameterLimit: typeof opts.parameterLimit === 'number' ? opts.parameterLimit : defaults.parameterLimit,
@@ -259,7 +235,7 @@ module.exports = function (str, opts) {
259
235
  var keys = Object.keys(tempObj);
260
236
  for (var i = 0; i < keys.length; ++i) {
261
237
  var key = keys[i];
262
- var newObj = parseKeys(key, tempObj[key], options, typeof str === 'string');
238
+ var newObj = parseKeys(key, tempObj[key], options);
263
239
  obj = utils.merge(obj, newObj, options);
264
240
  }
265
241
 
package/lib/stringify.js CHANGED
@@ -5,20 +5,19 @@ var formats = require('./formats');
5
5
  var has = Object.prototype.hasOwnProperty;
6
6
 
7
7
  var arrayPrefixGenerators = {
8
- brackets: function brackets(prefix) {
8
+ brackets: function brackets(prefix) { // eslint-disable-line func-name-matching
9
9
  return prefix + '[]';
10
10
  },
11
11
  comma: 'comma',
12
- indices: function indices(prefix, key) {
12
+ indices: function indices(prefix, key) { // eslint-disable-line func-name-matching
13
13
  return prefix + '[' + key + ']';
14
14
  },
15
- repeat: function repeat(prefix) {
15
+ repeat: function repeat(prefix) { // eslint-disable-line func-name-matching
16
16
  return prefix;
17
17
  }
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]);
@@ -40,14 +39,22 @@ var defaults = {
40
39
  formatter: formats.formatters[defaultFormat],
41
40
  // deprecated
42
41
  indices: false,
43
- serializeDate: function serializeDate(date) {
42
+ serializeDate: function serializeDate(date) { // eslint-disable-line func-name-matching
44
43
  return toISO.call(date);
45
44
  },
46
45
  skipNulls: false,
47
46
  strictNullHandling: false
48
47
  };
49
48
 
50
- var stringify = function stringify(
49
+ var isNonNullishPrimitive = function isNonNullishPrimitive(v) { // eslint-disable-line func-name-matching
50
+ return typeof v === 'string'
51
+ || typeof v === 'number'
52
+ || typeof v === 'boolean'
53
+ || typeof v === 'symbol'
54
+ || typeof v === 'bigint'; // eslint-disable-line valid-typeof
55
+ };
56
+
57
+ var stringify = function stringify( // eslint-disable-line func-name-matching
51
58
  object,
52
59
  prefix,
53
60
  generateArrayPrefix,
@@ -79,17 +86,9 @@ var stringify = function stringify(
79
86
  obj = '';
80
87
  }
81
88
 
82
- if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean' || utils.isBuffer(obj)) {
89
+ if (isNonNullishPrimitive(obj) || utils.isBuffer(obj)) {
83
90
  if (encoder) {
84
91
  var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset);
85
- if (generateArrayPrefix === 'comma' && encodeValuesOnly) {
86
- var valuesArray = split.call(String(obj), ',');
87
- var valuesJoined = '';
88
- for (var i = 0; i < valuesArray.length; ++i) {
89
- valuesJoined += (i === 0 ? '' : ',') + formatter(encoder(valuesArray[i], defaults.encoder, charset));
90
- }
91
- return [formatter(keyValue) + '=' + valuesJoined];
92
- }
93
92
  return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder, charset))];
94
93
  }
95
94
  return [formatter(prefix) + '=' + formatter(String(obj))];
@@ -109,9 +108,8 @@ var stringify = function stringify(
109
108
  objKeys = sort ? keys.sort(sort) : keys;
110
109
  }
111
110
 
112
- for (var j = 0; j < objKeys.length; ++j) {
113
- var key = objKeys[j];
114
- 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];
115
113
 
116
114
  if (skipNulls && obj[key] === null) {
117
115
  continue;
@@ -119,7 +117,7 @@ var stringify = function stringify(
119
117
 
120
118
  if (isArray(obj)) {
121
119
  pushToArray(values, stringify(
122
- value,
120
+ obj[key],
123
121
  typeof generateArrayPrefix === 'function' ? generateArrayPrefix(prefix, key) : prefix,
124
122
  generateArrayPrefix,
125
123
  strictNullHandling,
@@ -135,7 +133,7 @@ var stringify = function stringify(
135
133
  ));
136
134
  } else {
137
135
  pushToArray(values, stringify(
138
- value,
136
+ obj[key],
139
137
  prefix + (allowDots ? '.' + key : '[' + key + ']'),
140
138
  generateArrayPrefix,
141
139
  strictNullHandling,
@@ -160,7 +158,7 @@ var normalizeStringifyOptions = function normalizeStringifyOptions(opts) {
160
158
  return defaults;
161
159
  }
162
160
 
163
- if (opts.encoder !== null && typeof opts.encoder !== 'undefined' && typeof opts.encoder !== 'function') {
161
+ if (opts.encoder !== null && opts.encoder !== undefined && typeof opts.encoder !== 'function') {
164
162
  throw new TypeError('Encoder has to be a function.');
165
163
  }
166
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
  };
@@ -126,7 +126,12 @@ var encode = function encode(str, defaultEncoder, charset) {
126
126
  return str;
127
127
  }
128
128
 
129
- var string = typeof str === 'string' ? str : String(str);
129
+ var string = str;
130
+ if (typeof str === 'symbol') {
131
+ string = Symbol.prototype.toString.call(str);
132
+ } else if (typeof str !== 'string') {
133
+ string = String(str);
134
+ }
130
135
 
131
136
  if (charset === 'iso-8859-1') {
132
137
  return escape(string).replace(/%u[0-9a-f]{4}/gi, function ($0) {
@@ -168,7 +173,6 @@ var encode = function encode(str, defaultEncoder, charset) {
168
173
 
169
174
  i += 1;
170
175
  c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF));
171
- /* eslint operator-linebreak: [2, "before"] */
172
176
  out += hexTable[0xF0 | (c >> 18)]
173
177
  + hexTable[0x80 | ((c >> 12) & 0x3F)]
174
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.7.3",
5
+ "version": "6.8.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.0.2",
32
+ "browserify": "^16.5.0",
33
+ "covert": "^1.1.1",
35
34
  "eclint": "^2.8.1",
36
- "eslint": "^8.6.0",
37
- "evalmd": "^0.0.19",
35
+ "eslint": "^6.1.0",
36
+ "evalmd": "^0.0.17",
38
37
  "for-each": "^0.3.3",
39
- "has-symbols": "^1.0.2",
40
- "iconv-lite": "^0.5.1",
41
- "in-publish": "^2.0.1",
42
- "mkdirp": "^0.5.4",
43
- "nyc": "^10.3.2",
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
- "test": "npm run --silent tests-only",
55
- "tests-only": "nyc tape 'test/**/*.js'",
56
- "posttest": "npx aud --production",
50
+ "test": "npm run --silent coverage",
51
+ "tests-only": "node test",
57
52
  "readme": "evalmd README.md",
58
- "postlint": "eclint check $(git ls-files | xargs find 2> /dev/null | grep -vE 'node_modules|\\.git')",
53
+ "postlint": "eclint check * lib/* test/*",
59
54
  "lint": "eslint lib/*.js test/*.js",
55
+ "coverage": "covert test",
60
56
  "dist": "mkdirp dist && browserify --standalone Qs lib/index.js > dist/qs.js"
61
57
  },
62
58
  "license": "BSD-3-Clause"
package/test/.eslintrc ADDED
@@ -0,0 +1,17 @@
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
+ "object-curly-newline": 0,
15
+ "sort-keys": 0
16
+ }
17
+ }
package/test/parse.js CHANGED
@@ -32,38 +32,6 @@ 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
-
67
35
  t.test('allows enabling dot notation', function (st) {
68
36
  st.deepEqual(qs.parse('a.b=c'), { 'a.b': 'c' });
69
37
  st.deepEqual(qs.parse('a.b=c', { allowDots: true }), { a: { b: 'c' } });
@@ -84,25 +52,13 @@ test('parse()', function (t) {
84
52
  st.end();
85
53
  });
86
54
 
87
- t.test('current behavior with depth = 0', function (st) {
88
- st.deepEqual(qs.parse('a[0]=b&a[1]=c', { depth: 0 }), { a: { '[0]': 'b', '[1]': 'c' } });
89
- st.deepEqual(qs.parse('a[0][0]=b&a[0][1]=c&a[1]=d&e=2', { depth: 0 }), { a: { '[0][0]': 'b', '[0][1]': 'c', '[1]': 'd' }, e: '2' });
90
- st.end();
91
- });
92
-
93
- t.test('uses original key when depth = 0', { skip: true, todo: true }, function (st) {
55
+ t.test('uses original key when depth = 0', function (st) {
94
56
  st.deepEqual(qs.parse('a[0]=b&a[1]=c', { depth: 0 }), { 'a[0]': 'b', 'a[1]': 'c' });
95
57
  st.deepEqual(qs.parse('a[0][0]=b&a[0][1]=c&a[1]=d&e=2', { depth: 0 }), { 'a[0][0]': 'b', 'a[0][1]': 'c', 'a[1]': 'd', e: '2' });
96
58
  st.end();
97
59
  });
98
60
 
99
- t.test('current behavior with depth = false', function (st) {
100
- st.deepEqual(qs.parse('a[0]=b&a[1]=c', { depth: false }), { a: ['b', 'c'] });
101
- st.deepEqual(qs.parse('a[0][0]=b&a[0][1]=c&a[1]=d&e=2', { depth: false }), { a: [['b', 'c'], 'd'], e: '2' });
102
- st.end();
103
- });
104
-
105
- t.test('uses original key when depth = false', { skip: true, todo: true }, function (st) {
61
+ t.test('uses original key when depth = false', function (st) {
106
62
  st.deepEqual(qs.parse('a[0]=b&a[1]=c', { depth: false }), { 'a[0]': 'b', 'a[1]': 'c' });
107
63
  st.deepEqual(qs.parse('a[0][0]=b&a[0][1]=c&a[1]=d&e=2', { depth: false }), { 'a[0][0]': 'b', 'a[0][1]': 'c', 'a[1]': 'd', e: '2' });
108
64
  st.end();
@@ -412,43 +368,6 @@ test('parse()', function (t) {
412
368
  st.end();
413
369
  });
414
370
 
415
- t.test('parses values with comma as array divider', function (st) {
416
- st.deepEqual(qs.parse({ foo: 'bar,tee' }, { comma: false }), { foo: 'bar,tee' });
417
- st.deepEqual(qs.parse({ foo: 'bar,tee' }, { comma: true }), { foo: ['bar', 'tee'] });
418
- st.end();
419
- });
420
-
421
- t.test('use number decoder, parses string that has one number with comma option enabled', function (st) {
422
- var decoder = function (str, defaultDecoder, charset, type) {
423
- if (!isNaN(Number(str))) {
424
- return parseFloat(str);
425
- }
426
- return defaultDecoder(str, defaultDecoder, charset, type);
427
- };
428
-
429
- st.deepEqual(qs.parse('foo=1', { comma: true, decoder: decoder }), { foo: 1 });
430
- st.deepEqual(qs.parse('foo=0', { comma: true, decoder: decoder }), { foo: 0 });
431
-
432
- st.end();
433
- });
434
-
435
- t.test('parses brackets holds array of arrays when having two parts of strings with comma as array divider', function (st) {
436
- st.deepEqual(qs.parse('foo[]=1,2,3&foo[]=4,5,6', { comma: true }), { foo: [['1', '2', '3'], ['4', '5', '6']] });
437
- st.deepEqual(qs.parse('foo[]=1,2,3&foo[]=', { comma: true }), { foo: [['1', '2', '3'], ''] });
438
- st.deepEqual(qs.parse('foo[]=1,2,3&foo[]=,', { comma: true }), { foo: [['1', '2', '3'], ['', '']] });
439
- st.deepEqual(qs.parse('foo[]=1,2,3&foo[]=a', { comma: true }), { foo: [['1', '2', '3'], 'a'] });
440
-
441
- st.end();
442
- });
443
-
444
- t.test('parses comma delimited array while having percent-encoded comma treated as normal text', function (st) {
445
- st.deepEqual(qs.parse('foo=a%2Cb', { comma: true }), { foo: 'a,b' });
446
- st.deepEqual(qs.parse('foo=a%2C%20b,d', { comma: true }), { foo: ['a, b', 'd'] });
447
- st.deepEqual(qs.parse('foo=a%2C%20b,c%2C%20d', { comma: true }), { foo: ['a, b', 'c, d'] });
448
-
449
- st.end();
450
- });
451
-
452
371
  t.test('parses an object in dot notation', function (st) {
453
372
  var input = {
454
373
  'user.name': { 'pop[bob]': 3 },
@@ -625,73 +544,13 @@ test('parse()', function (t) {
625
544
 
626
545
  st.deepEqual(
627
546
  qs.parse('a[b]=c&a=toString', { plainObjects: true }),
628
- { __proto__: null, a: { __proto__: null, b: 'c', toString: true } },
547
+ { a: { b: 'c', toString: true } },
629
548
  'can overwrite prototype with plainObjects true'
630
549
  );
631
550
 
632
551
  st.end();
633
552
  });
634
553
 
635
- t.test('dunder proto is ignored', function (st) {
636
- var payload = 'categories[__proto__]=login&categories[__proto__]&categories[length]=42';
637
- var result = qs.parse(payload, { allowPrototypes: true });
638
-
639
- st.deepEqual(
640
- result,
641
- {
642
- categories: {
643
- length: '42'
644
- }
645
- },
646
- 'silent [[Prototype]] payload'
647
- );
648
-
649
- var plainResult = qs.parse(payload, { allowPrototypes: true, plainObjects: true });
650
-
651
- st.deepEqual(
652
- plainResult,
653
- {
654
- __proto__: null,
655
- categories: {
656
- __proto__: null,
657
- length: '42'
658
- }
659
- },
660
- 'silent [[Prototype]] payload: plain objects'
661
- );
662
-
663
- var query = qs.parse('categories[__proto__]=cats&categories[__proto__]=dogs&categories[some][json]=toInject', { allowPrototypes: true });
664
-
665
- st.notOk(Array.isArray(query.categories), 'is not an array');
666
- st.notOk(query.categories instanceof Array, 'is not instanceof an array');
667
- st.deepEqual(query.categories, { some: { json: 'toInject' } });
668
- st.equal(JSON.stringify(query.categories), '{"some":{"json":"toInject"}}', 'stringifies as a non-array');
669
-
670
- st.deepEqual(
671
- qs.parse('foo[__proto__][hidden]=value&foo[bar]=stuffs', { allowPrototypes: true }),
672
- {
673
- foo: {
674
- bar: 'stuffs'
675
- }
676
- },
677
- 'hidden values'
678
- );
679
-
680
- st.deepEqual(
681
- qs.parse('foo[__proto__][hidden]=value&foo[bar]=stuffs', { allowPrototypes: true, plainObjects: true }),
682
- {
683
- __proto__: null,
684
- foo: {
685
- __proto__: null,
686
- bar: 'stuffs'
687
- }
688
- },
689
- 'hidden values: plain objects'
690
- );
691
-
692
- st.end();
693
- });
694
-
695
554
  t.test('can return null objects', { skip: !Object.create }, function (st) {
696
555
  var expected = Object.create(null);
697
556
  expected.a = Object.create(null);
@@ -770,6 +629,7 @@ test('parse()', function (t) {
770
629
  });
771
630
 
772
631
  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
773
633
  st.deepEqual(qs.parse('utf8=' + urlEncodedNumCheckmark + '&' + urlEncodedOSlashInUtf8 + '=' + urlEncodedOSlashInUtf8, { charsetSentinel: true, charset: 'utf-8' }), { 'ø': 'ø' });
774
634
  st.end();
775
635
  });
@@ -790,6 +650,7 @@ test('parse()', function (t) {
790
650
  });
791
651
 
792
652
  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
793
654
  st.deepEqual(qs.parse('utf8=' + urlEncodedNumCheckmark + '&' + urlEncodedOSlashInUtf8 + '=' + urlEncodedOSlashInUtf8, { charsetSentinel: true }), { 'ø': 'ø' });
794
655
  st.end();
795
656
  });
package/test/stringify.js CHANGED
@@ -5,6 +5,8 @@ var qs = require('../');
5
5
  var utils = require('../lib/utils');
6
6
  var iconv = require('iconv-lite');
7
7
  var SaferBuffer = require('safer-buffer').Buffer;
8
+ var hasSymbols = require('has-symbols');
9
+ var hasBigInt = typeof BigInt === 'function';
8
10
 
9
11
  test('stringify()', function (t) {
10
12
  t.test('stringifies a querystring object', function (st) {
@@ -28,6 +30,39 @@ test('stringify()', function (t) {
28
30
  st.end();
29
31
  });
30
32
 
33
+ t.test('stringifies symbols', { skip: !hasSymbols() }, function (st) {
34
+ st.equal(qs.stringify(Symbol.iterator), '');
35
+ st.equal(qs.stringify([Symbol.iterator]), '0=Symbol%28Symbol.iterator%29');
36
+ st.equal(qs.stringify({ a: Symbol.iterator }), 'a=Symbol%28Symbol.iterator%29');
37
+ st.equal(
38
+ qs.stringify({ a: [Symbol.iterator] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
39
+ 'a[]=Symbol%28Symbol.iterator%29'
40
+ );
41
+ st.end();
42
+ });
43
+
44
+ t.test('stringifies bigints', { skip: !hasBigInt }, function (st) {
45
+ var three = BigInt(3); // eslint-disable-line new-cap
46
+ var encodeWithN = function (value, defaultEncoder, charset) {
47
+ var result = defaultEncoder(value, defaultEncoder, charset);
48
+ return typeof value === 'bigint' ? result + 'n' : result; // eslint-disable-line valid-typeof
49
+ };
50
+ st.equal(qs.stringify(three), '');
51
+ st.equal(qs.stringify([three]), '0=3');
52
+ st.equal(qs.stringify([three], { encoder: encodeWithN }), '0=3n');
53
+ st.equal(qs.stringify({ a: three }), 'a=3');
54
+ st.equal(qs.stringify({ a: three }, { encoder: encodeWithN }), 'a=3n');
55
+ st.equal(
56
+ qs.stringify({ a: [three] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
57
+ 'a[]=3'
58
+ );
59
+ st.equal(
60
+ qs.stringify({ a: [three] }, { encodeValuesOnly: true, encoder: encodeWithN, arrayFormat: 'brackets' }),
61
+ 'a[]=3n'
62
+ );
63
+ st.end();
64
+ });
65
+
31
66
  t.test('adds query prefix', function (st) {
32
67
  st.equal(qs.stringify({ a: 'b' }, { addQueryPrefix: true }), '?a=b');
33
68
  st.end();
@@ -97,10 +132,10 @@ test('stringify()', function (t) {
97
132
  });
98
133
 
99
134
  t.test('stringifies a nested array value', function (st) {
100
- st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true, arrayFormat: 'indices' }), 'a[b][0]=c&a[b][1]=d');
101
- st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a[b][]=c&a[b][]=d');
102
- st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true, arrayFormat: 'comma' }), 'a[b]=c,d');
103
- 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');
104
139
  st.end();
105
140
  });
106
141
 
@@ -108,7 +143,7 @@ test('stringify()', function (t) {
108
143
  st.equal(
109
144
  qs.stringify(
110
145
  { a: { b: ['c', 'd'] } },
111
- { allowDots: true, encodeValuesOnly: true, arrayFormat: 'indices' }
146
+ { allowDots: true, encode: false, arrayFormat: 'indices' }
112
147
  ),
113
148
  'a.b[0]=c&a.b[1]=d',
114
149
  'indices: stringifies with dots + indices'
@@ -116,7 +151,7 @@ test('stringify()', function (t) {
116
151
  st.equal(
117
152
  qs.stringify(
118
153
  { a: { b: ['c', 'd'] } },
119
- { allowDots: true, encodeValuesOnly: true, arrayFormat: 'brackets' }
154
+ { allowDots: true, encode: false, arrayFormat: 'brackets' }
120
155
  ),
121
156
  'a.b[]=c&a.b[]=d',
122
157
  'brackets: stringifies with dots + brackets'
@@ -124,7 +159,7 @@ test('stringify()', function (t) {
124
159
  st.equal(
125
160
  qs.stringify(
126
161
  { a: { b: ['c', 'd'] } },
127
- { allowDots: true, encodeValuesOnly: true, arrayFormat: 'comma' }
162
+ { allowDots: true, encode: false, arrayFormat: 'comma' }
128
163
  ),
129
164
  'a.b=c,d',
130
165
  'comma: stringifies with dots + comma'
@@ -132,7 +167,7 @@ test('stringify()', function (t) {
132
167
  st.equal(
133
168
  qs.stringify(
134
169
  { a: { b: ['c', 'd'] } },
135
- { allowDots: true, encodeValuesOnly: true }
170
+ { allowDots: true, encode: false }
136
171
  ),
137
172
  'a.b[0]=c&a.b[1]=d',
138
173
  'default: stringifies with dots + indices'
@@ -180,23 +215,17 @@ test('stringify()', function (t) {
180
215
 
181
216
  t.test('stringifies an array with mixed objects and primitives', function (st) {
182
217
  st.equal(
183
- qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'indices' }),
218
+ qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encode: false, arrayFormat: 'indices' }),
184
219
  'a[0][b]=1&a[1]=2&a[2]=3',
185
220
  'indices => indices'
186
221
  );
187
222
  st.equal(
188
- qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
223
+ qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encode: false, arrayFormat: 'brackets' }),
189
224
  'a[][b]=1&a[]=2&a[]=3',
190
225
  'brackets => brackets'
191
226
  );
192
227
  st.equal(
193
- qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'comma' }),
194
- '???',
195
- 'brackets => brackets',
196
- { skip: 'TODO: figure out what this should do' }
197
- );
198
- st.equal(
199
- qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true }),
228
+ qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encode: false }),
200
229
  'a[0][b]=1&a[1]=2&a[2]=3',
201
230
  'default => indices'
202
231
  );
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.alloc ? Buffer.from('abc') : new Buffer('abc');
133
+ var buffer = Buffer.from ? 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
  });
package/.nycrc DELETED
@@ -1,13 +0,0 @@
1
- {
2
- "all": true,
3
- "check-coverage": false,
4
- "reporter": ["text-summary", "text", "html", "json"],
5
- "lines": 86,
6
- "statements": 85.93,
7
- "functions": 82.43,
8
- "branches": 76.06,
9
- "exclude": [
10
- "coverage",
11
- "dist"
12
- ]
13
- }