qs 6.3.2 → 6.3.3

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 ADDED
@@ -0,0 +1,44 @@
1
+ root = true
2
+
3
+ [*]
4
+ indent_style = space
5
+ indent_size = 4
6
+ end_of_line = lf
7
+ charset = utf-8
8
+ trim_trailing_whitespace = true
9
+ insert_final_newline = true
10
+ max_line_length = 160
11
+ quote_type = single
12
+
13
+ [test/*]
14
+ max_line_length = off
15
+
16
+ [*.md]
17
+ indent_size = off
18
+ max_line_length = off
19
+
20
+ [*.json]
21
+ max_line_length = off
22
+
23
+ [Makefile]
24
+ max_line_length = off
25
+
26
+ [CHANGELOG.md]
27
+ indent_style = space
28
+ indent_size = 2
29
+
30
+ [LICENSE]
31
+ indent_size = 2
32
+ max_line_length = off
33
+
34
+ [coverage/**/*]
35
+ indent_size = off
36
+ indent_style = off
37
+ indent = off
38
+ max_line_length = off
39
+
40
+ [dist/*]
41
+ max_line_length = off
42
+
43
+ [.nycrc]
44
+ indent_style = tab
package/.eslintrc CHANGED
@@ -3,17 +3,35 @@
3
3
 
4
4
  "extends": "@ljharb",
5
5
 
6
+ "ignorePatterns": [
7
+ "dist/",
8
+ ],
9
+
6
10
  "rules": {
7
- "complexity": [2, 25],
11
+ "complexity": [2, 29],
8
12
  "consistent-return": 1,
13
+ "func-name-matching": 0,
9
14
  "id-length": [2, { "min": 1, "max": 25, "properties": "never" }],
10
15
  "indent": [2, 4],
11
- "max-params": [2, 11],
12
- "max-statements": [2, 42],
13
- "no-extra-parens": 1,
16
+ "max-lines-per-function": 0,
17
+ "max-params": [2, 12],
18
+ "max-statements": [2, 45],
19
+ "multiline-comment-style": 0,
14
20
  "no-continue": 1,
15
21
  "no-magic-numbers": 0,
22
+ "no-param-reassign": 1,
16
23
  "no-restricted-syntax": [2, "BreakStatement", "DebuggerStatement", "ForInStatement", "LabeledStatement", "WithStatement"],
17
- "operator-linebreak": 1
18
- }
24
+ },
25
+
26
+ "overrides": [
27
+ {
28
+ "files": "test/**",
29
+ "rules": {
30
+ "max-lines-per-function": 0,
31
+ "max-statements": 0,
32
+ "no-extend-native": 0,
33
+ "function-paren-newline": 0,
34
+ },
35
+ },
36
+ ],
19
37
  }
@@ -0,0 +1,12 @@
1
+ # These are supported funding model platforms
2
+
3
+ github: [ljharb]
4
+ patreon: # Replace with a single Patreon username
5
+ open_collective: # Replace with a single Open Collective username
6
+ ko_fi: # Replace with a single Ko-fi username
7
+ tidelift: npm/qs
8
+ community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9
+ liberapay: # Replace with a single Liberapay username
10
+ issuehunt: # Replace with a single IssueHunt username
11
+ otechie: # Replace with a single Otechie username
12
+ custom: # Replace with a single custom sponsorship URL
package/.nycrc ADDED
@@ -0,0 +1,13 @@
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
+ }
package/CHANGELOG.md CHANGED
@@ -1,3 +1,23 @@
1
+ ## **6.3.3**
2
+ - [Fix] `parse`: ignore `__proto__` keys (#428)
3
+ - [Fix] fix for an impossible situation: when the formatter is called with a non-string value
4
+ - [Fix] `utils.merge`: avoid a crash with a null target and an array source
5
+ - [Fix]` `utils.merge`: avoid a crash with a null target and a truthy non-array source
6
+ - [Fix] `stringify`: fix a crash with `strictNullHandling` and a custom `filter`/`serializeDate` (#279)
7
+ - [Fix] `utils`: `merge`: fix crash when `source` is a truthy primitive & no options are provided
8
+ - [Fix] when `parseArrays` is false, properly handle keys ending in `[]`
9
+ - [Robustness] `stringify`: avoid relying on a global `undefined` (#427)
10
+ - [Refactor] use cached `Array.isArray`
11
+ - [Refactor] `stringify`: Avoid arr = arr.concat(...), push to the existing instance (#269)
12
+ - [Docs] Clarify the need for "arrayLimit" option
13
+ - [meta] fix README.md (#399)
14
+ - [meta] Clean up license text so it’s properly detected as BSD-3-Clause
15
+ - [meta] add FUNDING.yml
16
+ - [actions] backport actions from main
17
+ - [Tests] use `safer-buffer` instead of `Buffer` constructor
18
+ - [Tests] remove nonexistent tape option
19
+ - [Dev Deps] backport from main
20
+
1
21
  ## **6.3.2**
2
22
  - [Fix] follow `allowPrototypes` option during merge (#201, #200)
3
23
  - [Dev Deps] update `eslint`
package/LICENSE.md ADDED
@@ -0,0 +1,29 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2014, Nathan LaFreniere and other [contributors](https://github.com/ljharb/qs/graphs/contributors)
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ 3. Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/README.md CHANGED
@@ -169,7 +169,7 @@ assert.deepEqual(withIndexedEmptyString, { a: ['b', '', 'c'] });
169
169
  ```
170
170
 
171
171
  **qs** will also limit specifying indices in an array to a maximum index of `20`. Any array members with an index of greater than `20` will
172
- instead be converted to an object with the index as the key:
172
+ instead be converted to an object with the index as the key. This is needed to handle cases when someone sent, for example, `a[999999999]` and it will take significant time to iterate over this huge array.
173
173
 
174
174
  ```javascript
175
175
  var withMaxIndex = qs.parse('a[100]=b');
@@ -245,6 +245,30 @@ var decoded = qs.parse('x=z', { decoder: function (str) {
245
245
  }})
246
246
  ```
247
247
 
248
+ You can encode keys and values using different logic by using the type argument provided to the encoder:
249
+
250
+ ```javascript
251
+ var encoded = qs.stringify({ a: { b: 'c' } }, { encoder: function (str, defaultEncoder, charset, type) {
252
+ if (type === 'key') {
253
+ return // Encoded key
254
+ } else if (type === 'value') {
255
+ return // Encoded value
256
+ }
257
+ }})
258
+ ```
259
+
260
+ The type argument is also provided to the decoder:
261
+
262
+ ```javascript
263
+ var decoded = qs.parse('x=z', { decoder: function (str, defaultDecoder, charset, type) {
264
+ if (type === 'key') {
265
+ return // Decoded key
266
+ } else if (type === 'value') {
267
+ return // Decoded value
268
+ }
269
+ }})
270
+ ```
271
+
248
272
  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.
249
273
 
250
274
  When arrays are stringified, by default they are given explicit indices:
@@ -400,7 +424,7 @@ assert.equal(nullsSkipped, 'a=b');
400
424
 
401
425
  ### Dealing with special character sets
402
426
 
403
- By default the encoding and decoding of characters is done in `utf-8`. If you
427
+ By default the encoding and decoding of characters is done in `utf-8`. If you
404
428
  wish to encode querystrings to a different character set (i.e.
405
429
  [Shift JIS](https://en.wikipedia.org/wiki/Shift_JIS)) you can use the
406
430
  [`qs-iconv`](https://github.com/martinheidegger/qs-iconv) library:
package/bower.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "qs",
3
+ "main": "dist/qs.js",
4
+ "homepage": "https://github.com/hapijs/qs",
5
+ "authors": [
6
+ "Nathan LaFreniere <quitlahok@gmail.com>"
7
+ ],
8
+ "description": "A querystring parser that supports nesting and arrays, with a depth limit",
9
+ "keywords": [
10
+ "querystring",
11
+ "qs"
12
+ ],
13
+ "license": "BSD-3-Clause",
14
+ "ignore": [
15
+ "**/.*",
16
+ "node_modules",
17
+ "bower_components",
18
+ "test",
19
+ "tests"
20
+ ]
21
+ }
package/component.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "qs",
3
+ "repository": "hapijs/qs",
4
+ "description": "query-string parser / stringifier with nesting support",
5
+ "version": "6.3.3",
6
+ "keywords": ["querystring", "query", "parser"],
7
+ "main": "lib/index.js",
8
+ "scripts": [
9
+ "lib/index.js",
10
+ "lib/parse.js",
11
+ "lib/stringify.js",
12
+ "lib/utils.js"
13
+ ],
14
+ "license": "BSD-3-Clause"
15
+ }
package/dist/qs.js CHANGED
@@ -1,4 +1,4 @@
1
- (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Qs = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
1
+ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Qs = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
2
2
  'use strict';
3
3
 
4
4
  var replace = String.prototype.replace;
@@ -11,7 +11,7 @@ module.exports = {
11
11
  return replace.call(value, percentTwenties, '+');
12
12
  },
13
13
  RFC3986: function (value) {
14
- return value;
14
+ return String(value);
15
15
  }
16
16
  },
17
17
  RFC1738: 'RFC1738',
@@ -84,23 +84,25 @@ var parseObject = function parseObjectRecursive(chain, val, options) {
84
84
  var root = chain.shift();
85
85
 
86
86
  var obj;
87
- if (root === '[]') {
87
+ if (root === '[]' && options.parseArrays) {
88
88
  obj = [];
89
89
  obj = obj.concat(parseObject(chain, val, options));
90
90
  } else {
91
91
  obj = options.plainObjects ? Object.create(null) : {};
92
92
  var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;
93
93
  var index = parseInt(cleanRoot, 10);
94
- if (
95
- !isNaN(index) &&
96
- root !== cleanRoot &&
97
- String(index) === cleanRoot &&
98
- index >= 0 &&
99
- (options.parseArrays && index <= options.arrayLimit)
94
+ if (!options.parseArrays && cleanRoot === '') {
95
+ obj = { 0: val };
96
+ } else if (
97
+ !isNaN(index)
98
+ && root !== cleanRoot
99
+ && String(index) === cleanRoot
100
+ && index >= 0
101
+ && (options.parseArrays && index <= options.arrayLimit)
100
102
  ) {
101
103
  obj = [];
102
104
  obj[index] = parseObject(chain, val, options);
103
- } else {
105
+ } else if (cleanRoot !== '__proto__') {
104
106
  obj[cleanRoot] = parseObject(chain, val, options);
105
107
  }
106
108
  }
@@ -130,8 +132,7 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options) {
130
132
 
131
133
  var keys = [];
132
134
  if (parent) {
133
- // If we aren't using plain objects, optionally prefix keys
134
- // that would overwrite object prototype properties
135
+ // If we aren't using plain objects, optionally prefix keys that would overwrite object prototype properties
135
136
  if (!options.plainObjects && has.call(Object.prototype, parent)) {
136
137
  if (!options.allowPrototypes) {
137
138
  return;
@@ -207,31 +208,37 @@ var utils = require('./utils');
207
208
  var formats = require('./formats');
208
209
 
209
210
  var arrayPrefixGenerators = {
210
- brackets: function brackets(prefix) { // eslint-disable-line func-name-matching
211
+ brackets: function brackets(prefix) {
211
212
  return prefix + '[]';
212
213
  },
213
- indices: function indices(prefix, key) { // eslint-disable-line func-name-matching
214
+ indices: function indices(prefix, key) {
214
215
  return prefix + '[' + key + ']';
215
216
  },
216
- repeat: function repeat(prefix) { // eslint-disable-line func-name-matching
217
+ repeat: function repeat(prefix) {
217
218
  return prefix;
218
219
  }
219
220
  };
220
221
 
222
+ var isArray = Array.isArray;
223
+ var push = Array.prototype.push;
224
+ var pushToArray = function (arr, valueOrArray) {
225
+ push.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]);
226
+ };
227
+
221
228
  var toISO = Date.prototype.toISOString;
222
229
 
223
230
  var defaults = {
224
231
  delimiter: '&',
225
232
  encode: true,
226
233
  encoder: utils.encode,
227
- serializeDate: function serializeDate(date) { // eslint-disable-line func-name-matching
234
+ serializeDate: function serializeDate(date) {
228
235
  return toISO.call(date);
229
236
  },
230
237
  skipNulls: false,
231
238
  strictNullHandling: false
232
239
  };
233
240
 
234
- var stringify = function stringify( // eslint-disable-line func-name-matching
241
+ var stringify = function stringify(
235
242
  object,
236
243
  prefix,
237
244
  generateArrayPrefix,
@@ -249,7 +256,9 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
249
256
  obj = filter(prefix, obj);
250
257
  } else if (obj instanceof Date) {
251
258
  obj = serializeDate(obj);
252
- } else if (obj === null) {
259
+ }
260
+
261
+ if (obj === null) {
253
262
  if (strictNullHandling) {
254
263
  return encoder ? encoder(prefix) : prefix;
255
264
  }
@@ -271,7 +280,7 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
271
280
  }
272
281
 
273
282
  var objKeys;
274
- if (Array.isArray(filter)) {
283
+ if (isArray(filter)) {
275
284
  objKeys = filter;
276
285
  } else {
277
286
  var keys = Object.keys(obj);
@@ -285,8 +294,8 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
285
294
  continue;
286
295
  }
287
296
 
288
- if (Array.isArray(obj)) {
289
- values = values.concat(stringify(
297
+ if (isArray(obj)) {
298
+ pushToArray(values, stringify(
290
299
  obj[key],
291
300
  generateArrayPrefix(prefix, key),
292
301
  generateArrayPrefix,
@@ -300,7 +309,7 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
300
309
  formatter
301
310
  ));
302
311
  } else {
303
- values = values.concat(stringify(
312
+ pushToArray(values, stringify(
304
313
  obj[key],
305
314
  prefix + (allowDots ? '.' + key : '[' + key + ']'),
306
315
  generateArrayPrefix,
@@ -323,7 +332,7 @@ module.exports = function (object, opts) {
323
332
  var obj = object;
324
333
  var options = opts || {};
325
334
 
326
- if (options.encoder !== null && options.encoder !== undefined && typeof options.encoder !== 'function') {
335
+ if (options.encoder !== null && typeof options.encoder !== 'undefined' && typeof options.encoder !== 'function') {
327
336
  throw new TypeError('Encoder has to be a function.');
328
337
  }
329
338
 
@@ -331,12 +340,12 @@ module.exports = function (object, opts) {
331
340
  var strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : defaults.strictNullHandling;
332
341
  var skipNulls = typeof options.skipNulls === 'boolean' ? options.skipNulls : defaults.skipNulls;
333
342
  var encode = typeof options.encode === 'boolean' ? options.encode : defaults.encode;
334
- var encoder = encode ? (typeof options.encoder === 'function' ? options.encoder : defaults.encoder) : null;
343
+ var encoder = encode ? typeof options.encoder === 'function' ? options.encoder : defaults.encoder : null;
335
344
  var sort = typeof options.sort === 'function' ? options.sort : null;
336
345
  var allowDots = typeof options.allowDots === 'undefined' ? false : options.allowDots;
337
346
  var serializeDate = typeof options.serializeDate === 'function' ? options.serializeDate : defaults.serializeDate;
338
347
  if (typeof options.format === 'undefined') {
339
- options.format = formats.default;
348
+ options.format = formats['default'];
340
349
  } else if (!Object.prototype.hasOwnProperty.call(formats.formatters, options.format)) {
341
350
  throw new TypeError('Unknown format option provided.');
342
351
  }
@@ -347,7 +356,7 @@ module.exports = function (object, opts) {
347
356
  if (typeof options.filter === 'function') {
348
357
  filter = options.filter;
349
358
  obj = filter('', obj);
350
- } else if (Array.isArray(options.filter)) {
359
+ } else if (isArray(options.filter)) {
351
360
  filter = options.filter;
352
361
  objKeys = filter;
353
362
  }
@@ -383,8 +392,7 @@ module.exports = function (object, opts) {
383
392
  if (skipNulls && obj[key] === null) {
384
393
  continue;
385
394
  }
386
-
387
- keys = keys.concat(stringify(
395
+ pushToArray(keys, stringify(
388
396
  obj[key],
389
397
  key,
390
398
  generateArrayPrefix,
@@ -435,8 +443,8 @@ exports.merge = function (target, source, options) {
435
443
  if (typeof source !== 'object') {
436
444
  if (Array.isArray(target)) {
437
445
  target.push(source);
438
- } else if (typeof target === 'object') {
439
- if (options.plainObjects || options.allowPrototypes || !has.call(Object.prototype, source)) {
446
+ } else if (target && typeof target === 'object') {
447
+ if ((options && (options.plainObjects || options.allowPrototypes)) || !has.call(Object.prototype, source)) {
440
448
  target[source] = true;
441
449
  }
442
450
  } else {
@@ -446,7 +454,7 @@ exports.merge = function (target, source, options) {
446
454
  return target;
447
455
  }
448
456
 
449
- if (typeof target !== 'object') {
457
+ if (!target || typeof target !== 'object') {
450
458
  return [target].concat(source);
451
459
  }
452
460
 
@@ -504,13 +512,13 @@ exports.encode = function (str) {
504
512
  var c = string.charCodeAt(i);
505
513
 
506
514
  if (
507
- c === 0x2D || // -
508
- c === 0x2E || // .
509
- c === 0x5F || // _
510
- c === 0x7E || // ~
511
- (c >= 0x30 && c <= 0x39) || // 0-9
512
- (c >= 0x41 && c <= 0x5A) || // a-z
513
- (c >= 0x61 && c <= 0x7A) // A-Z
515
+ c === 0x2D // -
516
+ || c === 0x2E // .
517
+ || c === 0x5F // _
518
+ || c === 0x7E // ~
519
+ || (c >= 0x30 && c <= 0x39) // 0-9
520
+ || (c >= 0x41 && c <= 0x5A) // a-z
521
+ || (c >= 0x61 && c <= 0x7A) // A-Z
514
522
  ) {
515
523
  out += string.charAt(i);
516
524
  continue;
@@ -533,7 +541,11 @@ exports.encode = function (str) {
533
541
 
534
542
  i += 1;
535
543
  c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF));
536
- out += hexTable[0xF0 | (c >> 18)] + hexTable[0x80 | ((c >> 12) & 0x3F)] + hexTable[0x80 | ((c >> 6) & 0x3F)] + hexTable[0x80 | (c & 0x3F)]; // eslint-disable-line max-len
544
+ /* eslint operator-linebreak: [2, "before"] */
545
+ out += hexTable[0xF0 | (c >> 18)]
546
+ + hexTable[0x80 | ((c >> 12) & 0x3F)]
547
+ + hexTable[0x80 | ((c >> 6) & 0x3F)]
548
+ + hexTable[0x80 | (c & 0x3F)];
537
549
  }
538
550
 
539
551
  return out;
@@ -587,4 +599,4 @@ exports.isBuffer = function (obj) {
587
599
  };
588
600
 
589
601
  },{}]},{},[2])(2)
590
- });
602
+ });
package/lib/formats.js CHANGED
@@ -10,7 +10,7 @@ module.exports = {
10
10
  return replace.call(value, percentTwenties, '+');
11
11
  },
12
12
  RFC3986: function (value) {
13
- return value;
13
+ return String(value);
14
14
  }
15
15
  },
16
16
  RFC1738: 'RFC1738',
package/lib/parse.js CHANGED
@@ -50,23 +50,25 @@ var parseObject = function parseObjectRecursive(chain, val, options) {
50
50
  var root = chain.shift();
51
51
 
52
52
  var obj;
53
- if (root === '[]') {
53
+ if (root === '[]' && options.parseArrays) {
54
54
  obj = [];
55
55
  obj = obj.concat(parseObject(chain, val, options));
56
56
  } else {
57
57
  obj = options.plainObjects ? Object.create(null) : {};
58
58
  var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;
59
59
  var index = parseInt(cleanRoot, 10);
60
- if (
61
- !isNaN(index) &&
62
- root !== cleanRoot &&
63
- String(index) === cleanRoot &&
64
- index >= 0 &&
65
- (options.parseArrays && index <= options.arrayLimit)
60
+ if (!options.parseArrays && cleanRoot === '') {
61
+ obj = { 0: val };
62
+ } else if (
63
+ !isNaN(index)
64
+ && root !== cleanRoot
65
+ && String(index) === cleanRoot
66
+ && index >= 0
67
+ && (options.parseArrays && index <= options.arrayLimit)
66
68
  ) {
67
69
  obj = [];
68
70
  obj[index] = parseObject(chain, val, options);
69
- } else {
71
+ } else if (cleanRoot !== '__proto__') {
70
72
  obj[cleanRoot] = parseObject(chain, val, options);
71
73
  }
72
74
  }
@@ -96,8 +98,7 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options) {
96
98
 
97
99
  var keys = [];
98
100
  if (parent) {
99
- // If we aren't using plain objects, optionally prefix keys
100
- // that would overwrite object prototype properties
101
+ // If we aren't using plain objects, optionally prefix keys that would overwrite object prototype properties
101
102
  if (!options.plainObjects && has.call(Object.prototype, parent)) {
102
103
  if (!options.allowPrototypes) {
103
104
  return;
package/lib/stringify.js CHANGED
@@ -4,31 +4,37 @@ var utils = require('./utils');
4
4
  var formats = require('./formats');
5
5
 
6
6
  var arrayPrefixGenerators = {
7
- brackets: function brackets(prefix) { // eslint-disable-line func-name-matching
7
+ brackets: function brackets(prefix) {
8
8
  return prefix + '[]';
9
9
  },
10
- indices: function indices(prefix, key) { // eslint-disable-line func-name-matching
10
+ indices: function indices(prefix, key) {
11
11
  return prefix + '[' + key + ']';
12
12
  },
13
- repeat: function repeat(prefix) { // eslint-disable-line func-name-matching
13
+ repeat: function repeat(prefix) {
14
14
  return prefix;
15
15
  }
16
16
  };
17
17
 
18
+ var isArray = Array.isArray;
19
+ var push = Array.prototype.push;
20
+ var pushToArray = function (arr, valueOrArray) {
21
+ push.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]);
22
+ };
23
+
18
24
  var toISO = Date.prototype.toISOString;
19
25
 
20
26
  var defaults = {
21
27
  delimiter: '&',
22
28
  encode: true,
23
29
  encoder: utils.encode,
24
- serializeDate: function serializeDate(date) { // eslint-disable-line func-name-matching
30
+ serializeDate: function serializeDate(date) {
25
31
  return toISO.call(date);
26
32
  },
27
33
  skipNulls: false,
28
34
  strictNullHandling: false
29
35
  };
30
36
 
31
- var stringify = function stringify( // eslint-disable-line func-name-matching
37
+ var stringify = function stringify(
32
38
  object,
33
39
  prefix,
34
40
  generateArrayPrefix,
@@ -46,7 +52,9 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
46
52
  obj = filter(prefix, obj);
47
53
  } else if (obj instanceof Date) {
48
54
  obj = serializeDate(obj);
49
- } else if (obj === null) {
55
+ }
56
+
57
+ if (obj === null) {
50
58
  if (strictNullHandling) {
51
59
  return encoder ? encoder(prefix) : prefix;
52
60
  }
@@ -68,7 +76,7 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
68
76
  }
69
77
 
70
78
  var objKeys;
71
- if (Array.isArray(filter)) {
79
+ if (isArray(filter)) {
72
80
  objKeys = filter;
73
81
  } else {
74
82
  var keys = Object.keys(obj);
@@ -82,8 +90,8 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
82
90
  continue;
83
91
  }
84
92
 
85
- if (Array.isArray(obj)) {
86
- values = values.concat(stringify(
93
+ if (isArray(obj)) {
94
+ pushToArray(values, stringify(
87
95
  obj[key],
88
96
  generateArrayPrefix(prefix, key),
89
97
  generateArrayPrefix,
@@ -97,7 +105,7 @@ var stringify = function stringify( // eslint-disable-line func-name-matching
97
105
  formatter
98
106
  ));
99
107
  } else {
100
- values = values.concat(stringify(
108
+ pushToArray(values, stringify(
101
109
  obj[key],
102
110
  prefix + (allowDots ? '.' + key : '[' + key + ']'),
103
111
  generateArrayPrefix,
@@ -120,7 +128,7 @@ module.exports = function (object, opts) {
120
128
  var obj = object;
121
129
  var options = opts || {};
122
130
 
123
- if (options.encoder !== null && options.encoder !== undefined && typeof options.encoder !== 'function') {
131
+ if (options.encoder !== null && typeof options.encoder !== 'undefined' && typeof options.encoder !== 'function') {
124
132
  throw new TypeError('Encoder has to be a function.');
125
133
  }
126
134
 
@@ -128,12 +136,12 @@ module.exports = function (object, opts) {
128
136
  var strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : defaults.strictNullHandling;
129
137
  var skipNulls = typeof options.skipNulls === 'boolean' ? options.skipNulls : defaults.skipNulls;
130
138
  var encode = typeof options.encode === 'boolean' ? options.encode : defaults.encode;
131
- var encoder = encode ? (typeof options.encoder === 'function' ? options.encoder : defaults.encoder) : null;
139
+ var encoder = encode ? typeof options.encoder === 'function' ? options.encoder : defaults.encoder : null;
132
140
  var sort = typeof options.sort === 'function' ? options.sort : null;
133
141
  var allowDots = typeof options.allowDots === 'undefined' ? false : options.allowDots;
134
142
  var serializeDate = typeof options.serializeDate === 'function' ? options.serializeDate : defaults.serializeDate;
135
143
  if (typeof options.format === 'undefined') {
136
- options.format = formats.default;
144
+ options.format = formats['default'];
137
145
  } else if (!Object.prototype.hasOwnProperty.call(formats.formatters, options.format)) {
138
146
  throw new TypeError('Unknown format option provided.');
139
147
  }
@@ -144,7 +152,7 @@ module.exports = function (object, opts) {
144
152
  if (typeof options.filter === 'function') {
145
153
  filter = options.filter;
146
154
  obj = filter('', obj);
147
- } else if (Array.isArray(options.filter)) {
155
+ } else if (isArray(options.filter)) {
148
156
  filter = options.filter;
149
157
  objKeys = filter;
150
158
  }
@@ -180,8 +188,7 @@ module.exports = function (object, opts) {
180
188
  if (skipNulls && obj[key] === null) {
181
189
  continue;
182
190
  }
183
-
184
- keys = keys.concat(stringify(
191
+ pushToArray(keys, stringify(
185
192
  obj[key],
186
193
  key,
187
194
  generateArrayPrefix,
package/lib/utils.js CHANGED
@@ -30,8 +30,8 @@ exports.merge = function (target, source, options) {
30
30
  if (typeof source !== 'object') {
31
31
  if (Array.isArray(target)) {
32
32
  target.push(source);
33
- } else if (typeof target === 'object') {
34
- if (options.plainObjects || options.allowPrototypes || !has.call(Object.prototype, source)) {
33
+ } else if (target && typeof target === 'object') {
34
+ if ((options && (options.plainObjects || options.allowPrototypes)) || !has.call(Object.prototype, source)) {
35
35
  target[source] = true;
36
36
  }
37
37
  } else {
@@ -41,7 +41,7 @@ exports.merge = function (target, source, options) {
41
41
  return target;
42
42
  }
43
43
 
44
- if (typeof target !== 'object') {
44
+ if (!target || typeof target !== 'object') {
45
45
  return [target].concat(source);
46
46
  }
47
47
 
@@ -99,13 +99,13 @@ exports.encode = function (str) {
99
99
  var c = string.charCodeAt(i);
100
100
 
101
101
  if (
102
- c === 0x2D || // -
103
- c === 0x2E || // .
104
- c === 0x5F || // _
105
- c === 0x7E || // ~
106
- (c >= 0x30 && c <= 0x39) || // 0-9
107
- (c >= 0x41 && c <= 0x5A) || // a-z
108
- (c >= 0x61 && c <= 0x7A) // A-Z
102
+ c === 0x2D // -
103
+ || c === 0x2E // .
104
+ || c === 0x5F // _
105
+ || c === 0x7E // ~
106
+ || (c >= 0x30 && c <= 0x39) // 0-9
107
+ || (c >= 0x41 && c <= 0x5A) // a-z
108
+ || (c >= 0x61 && c <= 0x7A) // A-Z
109
109
  ) {
110
110
  out += string.charAt(i);
111
111
  continue;
@@ -128,7 +128,11 @@ exports.encode = function (str) {
128
128
 
129
129
  i += 1;
130
130
  c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF));
131
- out += hexTable[0xF0 | (c >> 18)] + hexTable[0x80 | ((c >> 12) & 0x3F)] + hexTable[0x80 | ((c >> 6) & 0x3F)] + hexTable[0x80 | (c & 0x3F)]; // eslint-disable-line max-len
131
+ /* eslint operator-linebreak: [2, "before"] */
132
+ out += hexTable[0xF0 | (c >> 18)]
133
+ + hexTable[0x80 | ((c >> 12) & 0x3F)]
134
+ + hexTable[0x80 | ((c >> 6) & 0x3F)]
135
+ + hexTable[0x80 | (c & 0x3F)];
132
136
  }
133
137
 
134
138
  return out;
package/package.json CHANGED
@@ -1,50 +1,54 @@
1
1
  {
2
- "name": "qs",
3
- "description": "A querystring parser that supports nesting and arrays, with a depth limit",
4
- "homepage": "https://github.com/ljharb/qs",
5
- "version": "6.3.2",
6
- "repository": {
7
- "type": "git",
8
- "url": "https://github.com/ljharb/qs.git"
9
- },
10
- "main": "lib/index.js",
11
- "contributors": [
12
- {
13
- "name": "Jordan Harband",
14
- "email": "ljharb@gmail.com",
15
- "url": "http://ljharb.codes"
16
- }
17
- ],
18
- "keywords": [
19
- "querystring",
20
- "qs"
21
- ],
22
- "engines": {
23
- "node": ">=0.6"
24
- },
25
- "dependencies": {},
26
- "devDependencies": {
27
- "@ljharb/eslint-config": "^11.0.0",
28
- "browserify": "^14.1.0",
29
- "covert": "^1.1.0",
30
- "eslint": "^3.17.0",
31
- "evalmd": "^0.0.17",
32
- "iconv-lite": "^0.4.15",
33
- "mkdirp": "^0.5.1",
34
- "parallelshell": "^2.0.0",
35
- "qs-iconv": "^1.0.4",
36
- "safe-publish-latest": "^1.1.1",
37
- "tape": "^4.6.3"
38
- },
39
- "scripts": {
40
- "prepublish": "safe-publish-latest && npm run dist",
41
- "pretest": "npm run --silent readme && npm run --silent lint",
42
- "test": "npm run --silent coverage",
43
- "tests-only": "node test",
44
- "readme": "evalmd README.md",
45
- "lint": "eslint lib/*.js test/*.js",
46
- "coverage": "covert test",
47
- "dist": "mkdirp dist && browserify --standalone Qs lib/index.js > dist/qs.js"
48
- },
49
- "license": "BSD-3-Clause"
2
+ "name": "qs",
3
+ "description": "A querystring parser that supports nesting and arrays, with a depth limit",
4
+ "homepage": "https://github.com/ljharb/qs",
5
+ "version": "6.3.3",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/ljharb/qs.git"
9
+ },
10
+ "main": "lib/index.js",
11
+ "contributors": [
12
+ {
13
+ "name": "Jordan Harband",
14
+ "email": "ljharb@gmail.com",
15
+ "url": "http://ljharb.codes"
16
+ }
17
+ ],
18
+ "keywords": [
19
+ "querystring",
20
+ "qs"
21
+ ],
22
+ "engines": {
23
+ "node": ">=0.6"
24
+ },
25
+ "devDependencies": {
26
+ "@ljharb/eslint-config": "^20.1.0",
27
+ "aud": "^1.1.5",
28
+ "browserify": "^16.5.2",
29
+ "eclint": "^2.8.1",
30
+ "eslint": "^8.6.0",
31
+ "evalmd": "^0.0.17",
32
+ "iconv-lite": "^0.4.24",
33
+ "in-publish": "^2.0.1",
34
+ "mkdirp": "^0.5.1",
35
+ "nyc": "^10.3.2",
36
+ "qs-iconv": "^1.0.4",
37
+ "safe-publish-latest": "^2.0.0",
38
+ "safer-buffer": "^2.1.2",
39
+ "tape": "^5.4.0"
40
+ },
41
+ "scripts": {
42
+ "prepublishOnly": "safe-publish-latest && npm run dist",
43
+ "prepublish": "not-in-publish || npm run prepublishOnly",
44
+ "pretest": "npm run --silent readme && npm run --silent lint",
45
+ "test": "npm run --silent tests-only",
46
+ "tests-only": "nyc tape 'test/**/*.js'",
47
+ "posttest": "aud --production",
48
+ "readme": "evalmd README.md",
49
+ "postlint": "eclint check $(git ls-files | xargs find 2> /dev/null | grep -vE 'node_modules|\\.git')",
50
+ "lint": "eslint --ext=js,mjs .",
51
+ "dist": "mkdirp dist && browserify --standalone Qs lib/index.js > dist/qs.js"
52
+ },
53
+ "license": "BSD-3-Clause"
50
54
  }
package/test/parse.js CHANGED
@@ -3,6 +3,7 @@
3
3
  var test = require('tape');
4
4
  var qs = require('../');
5
5
  var iconv = require('iconv-lite');
6
+ var SaferBuffer = require('safer-buffer').Buffer;
6
7
 
7
8
  test('parse()', function (t) {
8
9
  t.test('parses a simple string', function (st) {
@@ -230,7 +231,7 @@ test('parse()', function (t) {
230
231
  });
231
232
 
232
233
  t.test('parses buffers correctly', function (st) {
233
- var b = new Buffer('test');
234
+ var b = SaferBuffer.from('test');
234
235
  st.deepEqual(qs.parse({ a: b }), { a: b });
235
236
  st.end();
236
237
  });
@@ -255,7 +256,7 @@ test('parse()', function (t) {
255
256
  st.end();
256
257
  });
257
258
 
258
- t.test('should not throw when a native prototype has an enumerable property', { parallel: false }, function (st) {
259
+ t.test('should not throw when a native prototype has an enumerable property', function (st) {
259
260
  Object.prototype.crash = '';
260
261
  Array.prototype.crash = '';
261
262
  st.doesNotThrow(qs.parse.bind(null, 'a=b'));
@@ -300,7 +301,14 @@ test('parse()', function (t) {
300
301
  });
301
302
 
302
303
  t.test('allows disabling array parsing', function (st) {
303
- st.deepEqual(qs.parse('a[0]=b&a[1]=c', { parseArrays: false }), { a: { 0: 'b', 1: 'c' } });
304
+ var indices = qs.parse('a[0]=b&a[1]=c', { parseArrays: false });
305
+ st.deepEqual(indices, { a: { 0: 'b', 1: 'c' } });
306
+ st.equal(Array.isArray(indices.a), false, 'parseArrays:false, indices case is not an array');
307
+
308
+ var emptyBrackets = qs.parse('a[]=b', { parseArrays: false });
309
+ st.deepEqual(emptyBrackets, { a: { 0: 'b' } });
310
+ st.equal(Array.isArray(emptyBrackets.a), false, 'parseArrays:false, empty brackets case is not an array');
311
+
304
312
  st.end();
305
313
  });
306
314
 
@@ -472,13 +480,73 @@ test('parse()', function (t) {
472
480
 
473
481
  st.deepEqual(
474
482
  qs.parse('a[b]=c&a=toString', { plainObjects: true }),
475
- { a: { b: 'c', toString: true } },
483
+ { __proto__: null, a: { __proto__: null, b: 'c', toString: true } },
476
484
  'can overwrite prototype with plainObjects true'
477
485
  );
478
486
 
479
487
  st.end();
480
488
  });
481
489
 
490
+ t.test('dunder proto is ignored', function (st) {
491
+ var payload = 'categories[__proto__]=login&categories[__proto__]&categories[length]=42';
492
+ var result = qs.parse(payload, { allowPrototypes: true });
493
+
494
+ st.deepEqual(
495
+ result,
496
+ {
497
+ categories: {
498
+ length: '42'
499
+ }
500
+ },
501
+ 'silent [[Prototype]] payload'
502
+ );
503
+
504
+ var plainResult = qs.parse(payload, { allowPrototypes: true, plainObjects: true });
505
+
506
+ st.deepEqual(
507
+ plainResult,
508
+ {
509
+ __proto__: null,
510
+ categories: {
511
+ __proto__: null,
512
+ length: '42'
513
+ }
514
+ },
515
+ 'silent [[Prototype]] payload: plain objects'
516
+ );
517
+
518
+ var query = qs.parse('categories[__proto__]=cats&categories[__proto__]=dogs&categories[some][json]=toInject', { allowPrototypes: true });
519
+
520
+ st.notOk(Array.isArray(query.categories), 'is not an array');
521
+ st.notOk(query.categories instanceof Array, 'is not instanceof an array');
522
+ st.deepEqual(query.categories, { some: { json: 'toInject' } });
523
+ st.equal(JSON.stringify(query.categories), '{"some":{"json":"toInject"}}', 'stringifies as a non-array');
524
+
525
+ st.deepEqual(
526
+ qs.parse('foo[__proto__][hidden]=value&foo[bar]=stuffs', { allowPrototypes: true }),
527
+ {
528
+ foo: {
529
+ bar: 'stuffs'
530
+ }
531
+ },
532
+ 'hidden values'
533
+ );
534
+
535
+ st.deepEqual(
536
+ qs.parse('foo[__proto__][hidden]=value&foo[bar]=stuffs', { allowPrototypes: true, plainObjects: true }),
537
+ {
538
+ __proto__: null,
539
+ foo: {
540
+ __proto__: null,
541
+ bar: 'stuffs'
542
+ }
543
+ },
544
+ 'hidden values: plain objects'
545
+ );
546
+
547
+ st.end();
548
+ });
549
+
482
550
  t.test('can return null objects', { skip: !Object.create }, function (st) {
483
551
  var expected = Object.create(null);
484
552
  expected.a = Object.create(null);
@@ -504,14 +572,14 @@ test('parse()', function (t) {
504
572
  result.push(parseInt(parts[1], 16));
505
573
  parts = reg.exec(str);
506
574
  }
507
- return iconv.decode(new Buffer(result), 'shift_jis').toString();
575
+ return iconv.decode(SaferBuffer.from(result), 'shift_jis').toString();
508
576
  }
509
577
  }), { 県: '大阪府' });
510
578
  st.end();
511
579
  });
512
580
 
513
581
  t.test('throws error with wrong decoder', function (st) {
514
- st.throws(function () {
582
+ st['throws'](function () {
515
583
  qs.parse({}, { decoder: 'string' });
516
584
  }, new TypeError('Decoder has to be a function.'));
517
585
  st.end();
package/test/stringify.js CHANGED
@@ -3,6 +3,7 @@
3
3
  var test = require('tape');
4
4
  var qs = require('../');
5
5
  var iconv = require('iconv-lite');
6
+ var SaferBuffer = require('safer-buffer').Buffer;
6
7
 
7
8
  test('stringify()', function (t) {
8
9
  t.test('stringifies a querystring object', function (st) {
@@ -325,8 +326,8 @@ test('stringify()', function (t) {
325
326
  });
326
327
 
327
328
  t.test('stringifies buffer values', function (st) {
328
- st.equal(qs.stringify({ a: new Buffer('test') }), 'a=test');
329
- st.equal(qs.stringify({ a: { b: new Buffer('test') } }), 'a%5Bb%5D=test');
329
+ st.equal(qs.stringify({ a: SaferBuffer.from('test') }), 'a=test');
330
+ st.equal(qs.stringify({ a: { b: SaferBuffer.from('test') } }), 'a%5Bb%5D=test');
330
331
  st.end();
331
332
  });
332
333
 
@@ -453,14 +454,14 @@ test('stringify()', function (t) {
453
454
  });
454
455
 
455
456
  t.test('throws error with wrong encoder', function (st) {
456
- st.throws(function () {
457
+ st['throws'](function () {
457
458
  qs.stringify({}, { encoder: 'string' });
458
459
  }, new TypeError('Encoder has to be a function.'));
459
460
  st.end();
460
461
  });
461
462
 
462
463
  t.test('can use custom encoder for a buffer object', { skip: typeof Buffer === 'undefined' }, function (st) {
463
- st.equal(qs.stringify({ a: new Buffer([1]) }, {
464
+ st.equal(qs.stringify({ a: SaferBuffer.from([1]) }, {
464
465
  encoder: function (buffer) {
465
466
  if (typeof buffer === 'string') {
466
467
  return buffer;
@@ -468,6 +469,12 @@ test('stringify()', function (t) {
468
469
  return String.fromCharCode(buffer.readUInt8(0) + 97);
469
470
  }
470
471
  }), 'a=b');
472
+
473
+ st.equal(qs.stringify({ a: SaferBuffer.from('a b') }, {
474
+ encoder: function (buffer) {
475
+ return buffer;
476
+ }
477
+ }), 'a=a b');
471
478
  st.end();
472
479
  });
473
480
 
@@ -483,7 +490,7 @@ test('stringify()', function (t) {
483
490
  mutatedDate.toISOString = function () {
484
491
  throw new SyntaxError();
485
492
  };
486
- st.throws(function () {
493
+ st['throws'](function () {
487
494
  mutatedDate.toISOString();
488
495
  }, SyntaxError);
489
496
  st.equal(
@@ -508,31 +515,54 @@ test('stringify()', function (t) {
508
515
  t.test('RFC 1738 spaces serialization', function (st) {
509
516
  st.equal(qs.stringify({ a: 'b c' }, { format: qs.formats.RFC1738 }), 'a=b+c');
510
517
  st.equal(qs.stringify({ 'a b': 'c d' }, { format: qs.formats.RFC1738 }), 'a+b=c+d');
518
+ st.equal(qs.stringify({ 'a b': SaferBuffer.from('a b') }, { format: qs.formats.RFC1738 }), 'a+b=a+b');
511
519
  st.end();
512
520
  });
513
521
 
514
522
  t.test('RFC 3986 spaces serialization', function (st) {
515
523
  st.equal(qs.stringify({ a: 'b c' }, { format: qs.formats.RFC3986 }), 'a=b%20c');
516
524
  st.equal(qs.stringify({ 'a b': 'c d' }, { format: qs.formats.RFC3986 }), 'a%20b=c%20d');
525
+ st.equal(qs.stringify({ 'a b': SaferBuffer.from('a b') }, { format: qs.formats.RFC3986 }), 'a%20b=a%20b');
517
526
  st.end();
518
527
  });
519
528
 
520
529
  t.test('Backward compatibility to RFC 3986', function (st) {
521
530
  st.equal(qs.stringify({ a: 'b c' }), 'a=b%20c');
531
+ st.equal(qs.stringify({ 'a b': SaferBuffer.from('a b') }), 'a%20b=a%20b');
522
532
  st.end();
523
533
  });
524
534
 
525
535
  t.test('Edge cases and unknown formats', function (st) {
526
- ['UFO1234', false, 1234, null, {}, []].forEach(
527
- function (format) {
528
- st.throws(
529
- function () {
530
- qs.stringify({ a: 'b c' }, { format: format });
531
- },
532
- new TypeError('Unknown format option provided.')
533
- );
534
- }
535
- );
536
+ ['UFO1234', false, 1234, null, {}, []].forEach(function (format) {
537
+ st['throws'](
538
+ function () {
539
+ qs.stringify({ a: 'b c' }, { format: format });
540
+ },
541
+ new TypeError('Unknown format option provided.')
542
+ );
543
+ });
536
544
  st.end();
537
545
  });
546
+
547
+ t.test('strictNullHandling works with custom filter', function (st) {
548
+ var filter = function (prefix, value) {
549
+ return value;
550
+ };
551
+
552
+ var options = { strictNullHandling: true, filter: filter };
553
+ st.equal(qs.stringify({ key: null }, options), 'key');
554
+ st.end();
555
+ });
556
+
557
+ t.test('strictNullHandling works with null serializeDate', function (st) {
558
+ var serializeDate = function () {
559
+ return null;
560
+ };
561
+ var options = { strictNullHandling: true, serializeDate: serializeDate };
562
+ var date = new Date();
563
+ st.equal(qs.stringify({ key: date }, options), 'key');
564
+ st.end();
565
+ });
566
+
567
+ t.end();
538
568
  });
package/test/utils.js CHANGED
@@ -4,6 +4,10 @@ var test = require('tape');
4
4
  var utils = require('../lib/utils');
5
5
 
6
6
  test('merge()', function (t) {
7
+ t.deepEqual(utils.merge(null, true), [null, true], 'merges true into null');
8
+
9
+ t.deepEqual(utils.merge(null, [42]), [null, 42], 'merges null into an array');
10
+
7
11
  t.deepEqual(utils.merge({ a: 'b' }, { a: 'c' }), { a: ['b', 'c'] }, 'merges two objects with the same key');
8
12
 
9
13
  var oneMerged = utils.merge({ foo: 'bar' }, { foo: { first: '123' } });
@@ -18,5 +22,8 @@ test('merge()', function (t) {
18
22
  var nestedArrays = utils.merge({ foo: ['baz'] }, { foo: ['bar', 'xyzzy'] });
19
23
  t.deepEqual(nestedArrays, { foo: ['baz', 'bar', 'xyzzy'] });
20
24
 
25
+ var noOptionsNonObjectSource = utils.merge({ foo: 'baz' }, 'bar');
26
+ t.deepEqual(noOptionsNonObjectSource, { foo: 'baz', bar: true });
27
+
21
28
  t.end();
22
29
  });
package/.eslintignore DELETED
@@ -1 +0,0 @@
1
- dist
package/LICENSE DELETED
@@ -1,28 +0,0 @@
1
- Copyright (c) 2014 Nathan LaFreniere and other contributors.
2
- All rights reserved.
3
-
4
- Redistribution and use in source and binary forms, with or without
5
- modification, are permitted provided that the following conditions are met:
6
- * Redistributions of source code must retain the above copyright
7
- notice, this list of conditions and the following disclaimer.
8
- * Redistributions in binary form must reproduce the above copyright
9
- notice, this list of conditions and the following disclaimer in the
10
- documentation and/or other materials provided with the distribution.
11
- * The names of any contributors may not be used to endorse or promote
12
- products derived from this software without specific prior written
13
- permission.
14
-
15
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY
19
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
-
26
- * * *
27
-
28
- The complete list of contributors can be found at: https://github.com/hapijs/qs/graphs/contributors
package/test/.eslintrc DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "rules": {
3
- "consistent-return": 2,
4
- "max-lines": 0,
5
- "max-nested-callbacks": [2, 3],
6
- "max-statements": 0,
7
- "no-extend-native": 0,
8
- "sort-keys": 1
9
- }
10
- }