query-string 6.13.8 → 7.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/index.d.ts +138 -4
  2. package/index.js +72 -5
  3. package/package.json +4 -2
  4. package/readme.md +168 -4
package/index.d.ts CHANGED
@@ -45,6 +45,30 @@ export interface ParseOptions {
45
45
  //=> {foo: ['1', '2', '3']}
46
46
  ```
47
47
 
48
+ - `bracket-separator`: Parse arrays (that are explicitly marked with brackets) with elements separated by a custom character:
49
+
50
+ ```
51
+ import queryString = require('query-string');
52
+
53
+ queryString.parse('foo[]', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
54
+ //=> {foo: []}
55
+
56
+ queryString.parse('foo[]=', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
57
+ //=> {foo: ['']}
58
+
59
+ queryString.parse('foo[]=1', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
60
+ //=> {foo: ['1']}
61
+
62
+ queryString.parse('foo[]=1|2|3', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
63
+ //=> {foo: ['1', '2', '3']}
64
+
65
+ queryString.parse('foo[]=1||3|||6', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
66
+ //=> {foo: ['1', '', 3, '', '', '6']}
67
+
68
+ queryString.parse('foo[]=1|2|3&bar=fluffy&baz[]=4', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
69
+ //=> {foo: ['1', '2', '3'], bar: 'fluffy', baz:['4']}
70
+ ```
71
+
48
72
  - `none`: Parse arrays with elements using duplicate keys:
49
73
 
50
74
  ```
@@ -54,7 +78,7 @@ export interface ParseOptions {
54
78
  //=> {foo: ['1', '2', '3']}
55
79
  ```
56
80
  */
57
- readonly arrayFormat?: 'bracket' | 'index' | 'comma' | 'separator' | 'none';
81
+ readonly arrayFormat?: 'bracket' | 'index' | 'comma' | 'separator' | 'bracket-separator' | 'none';
58
82
 
59
83
  /**
60
84
  The character used to separate array elements when using `{arrayFormat: 'separator'}`.
@@ -229,9 +253,14 @@ export interface StringifyOptions {
229
253
 
230
254
  queryString.stringify({foo: [1, 2, 3]}, {arrayFormat: 'comma'});
231
255
  //=> 'foo=1,2,3'
256
+
257
+ queryString.stringify({foo: [1, null, '']}, {arrayFormat: 'comma'});
258
+ //=> 'foo=1,,'
259
+ // Note that typing information for null values is lost
260
+ // and `.parse('foo=1,,')` would return `{foo: [1, '', '']}`.
232
261
  ```
233
262
 
234
- - `separator`: Serialize arrays by separating elements with character:
263
+ - `separator`: Serialize arrays by separating elements with character:
235
264
 
236
265
  ```
237
266
  import queryString = require('query-string');
@@ -240,6 +269,33 @@ export interface StringifyOptions {
240
269
  //=> 'foo=1|2|3'
241
270
  ```
242
271
 
272
+ - `bracket-separator`: Serialize arrays by explicitly post-fixing array names with brackets and separating elements with a custom character:
273
+
274
+ ```
275
+ import queryString = require('query-string');
276
+
277
+ queryString.stringify({foo: []}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
278
+ //=> 'foo[]'
279
+
280
+ queryString.stringify({foo: ['']}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
281
+ //=> 'foo[]='
282
+
283
+ queryString.stringify({foo: [1]}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
284
+ //=> 'foo[]=1'
285
+
286
+ queryString.stringify({foo: [1, 2, 3]}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
287
+ //=> 'foo[]=1|2|3'
288
+
289
+ queryString.stringify({foo: [1, '', 3, null, null, 6]}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
290
+ //=> 'foo[]=1||3|||6'
291
+
292
+ queryString.stringify({foo: [1, '', 3, null, null, 6]}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|', skipNull: true});
293
+ //=> 'foo[]=1||3|6'
294
+
295
+ queryString.stringify({foo: [1, 2, 3], bar: 'fluffy', baz: [4]}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
296
+ //=> 'foo[]=1|2|3&bar=fluffy&baz[]=4'
297
+ ```
298
+
243
299
  - `none`: Serialize arrays by using duplicate keys:
244
300
 
245
301
  ```
@@ -249,7 +305,7 @@ export interface StringifyOptions {
249
305
  //=> 'foo=1&foo=2&foo=3'
250
306
  ```
251
307
  */
252
- readonly arrayFormat?: 'bracket' | 'index' | 'comma' | 'separator' | 'none';
308
+ readonly arrayFormat?: 'bracket' | 'index' | 'comma' | 'separator' | 'bracket-separator' | 'none';
253
309
 
254
310
  /**
255
311
  The character used to separate array elements when using `{arrayFormat: 'separator'}`.
@@ -372,7 +428,7 @@ export interface UrlObject {
372
428
  /**
373
429
  Overrides queries in the `url` property.
374
430
  */
375
- readonly query: StringifiableRecord;
431
+ readonly query?: StringifiableRecord;
376
432
 
377
433
  /**
378
434
  Overrides the fragment identifier in the `url` property.
@@ -409,3 +465,81 @@ export function stringifyUrl(
409
465
  object: UrlObject,
410
466
  options?: StringifyOptions
411
467
  ): string;
468
+
469
+ /**
470
+ Pick query parameters from a URL.
471
+
472
+ @param url - The URL containing the query parameters to pick.
473
+ @param keys - The names of the query parameters to keep. All other query parameters will be removed from the URL.
474
+ @param filter - A filter predicate that will be provided the name of each query parameter and its value. The `parseNumbers` and `parseBooleans` options also affect `value`.
475
+
476
+ @returns The URL with the picked query parameters.
477
+
478
+ @example
479
+ ```
480
+ queryString.pick('https://foo.bar?foo=1&bar=2#hello', ['foo']);
481
+ //=> 'https://foo.bar?foo=1#hello'
482
+
483
+ queryString.pick('https://foo.bar?foo=1&bar=2#hello', (name, value) => value === 2, {parseNumbers: true});
484
+ //=> 'https://foo.bar?bar=2#hello'
485
+ ```
486
+ */
487
+ export function pick(
488
+ url: string,
489
+ keys: readonly string[],
490
+ options?: ParseOptions & StringifyOptions
491
+ ): string
492
+ export function pick(
493
+ url: string,
494
+ filter: (key: string, value: string | boolean | number) => boolean,
495
+ options?: {parseBooleans: true, parseNumbers: true} & ParseOptions & StringifyOptions
496
+ ): string
497
+ export function pick(
498
+ url: string,
499
+ filter: (key: string, value: string | boolean) => boolean,
500
+ options?: {parseBooleans: true} & ParseOptions & StringifyOptions
501
+ ): string
502
+ export function pick(
503
+ url: string,
504
+ filter: (key: string, value: string | number) => boolean,
505
+ options?: {parseNumbers: true} & ParseOptions & StringifyOptions
506
+ ): string
507
+
508
+ /**
509
+ Exclude query parameters from a URL. Like `.pick()` but reversed.
510
+
511
+ @param url - The URL containing the query parameters to exclude.
512
+ @param keys - The names of the query parameters to remove. All other query parameters will remain in the URL.
513
+ @param filter - A filter predicate that will be provided the name of each query parameter and its value. The `parseNumbers` and `parseBooleans` options also affect `value`.
514
+
515
+ @returns The URL without the excluded the query parameters.
516
+
517
+ @example
518
+ ```
519
+ queryString.exclude('https://foo.bar?foo=1&bar=2#hello', ['foo']);
520
+ //=> 'https://foo.bar?bar=2#hello'
521
+
522
+ queryString.exclude('https://foo.bar?foo=1&bar=2#hello', (name, value) => value === 2, {parseNumbers: true});
523
+ //=> 'https://foo.bar?foo=1#hello'
524
+ ```
525
+ */
526
+ export function exclude(
527
+ url: string,
528
+ keys: readonly string[],
529
+ options?: ParseOptions & StringifyOptions
530
+ ): string
531
+ export function exclude(
532
+ url: string,
533
+ filter: (key: string, value: string | boolean | number) => boolean,
534
+ options?: {parseBooleans: true, parseNumbers: true} & ParseOptions & StringifyOptions
535
+ ): string
536
+ export function exclude(
537
+ url: string,
538
+ filter: (key: string, value: string | boolean) => boolean,
539
+ options?: {parseBooleans: true} & ParseOptions & StringifyOptions
540
+ ): string
541
+ export function exclude(
542
+ url: string,
543
+ filter: (key: string, value: string | number) => boolean,
544
+ options?: {parseNumbers: true} & ParseOptions & StringifyOptions
545
+ ): string
package/index.js CHANGED
@@ -2,9 +2,12 @@
2
2
  const strictUriEncode = require('strict-uri-encode');
3
3
  const decodeComponent = require('decode-uri-component');
4
4
  const splitOnFirst = require('split-on-first');
5
+ const filterObject = require('filter-obj');
5
6
 
6
7
  const isNullOrUndefined = value => value === null || value === undefined;
7
8
 
9
+ const encodeFragmentIdentifier = Symbol('encodeFragmentIdentifier');
10
+
8
11
  function encoderForArrayFormat(options) {
9
12
  switch (options.arrayFormat) {
10
13
  case 'index':
@@ -48,17 +51,30 @@ function encoderForArrayFormat(options) {
48
51
 
49
52
  case 'comma':
50
53
  case 'separator':
54
+ case 'bracket-separator': {
55
+ const keyValueSep = options.arrayFormat === 'bracket-separator' ?
56
+ '[]=' :
57
+ '=';
58
+
51
59
  return key => (result, value) => {
52
- if (value === null || value === undefined || value.length === 0) {
60
+ if (
61
+ value === undefined ||
62
+ (options.skipNull && value === null) ||
63
+ (options.skipEmptyString && value === '')
64
+ ) {
53
65
  return result;
54
66
  }
55
67
 
68
+ // Translate null to an empty string so that it doesn't serialize as 'null'
69
+ value = value === null ? '' : value;
70
+
56
71
  if (result.length === 0) {
57
- return [[encode(key, options), '=', encode(value, options)].join('')];
72
+ return [[encode(key, options), keyValueSep, encode(value, options)].join('')];
58
73
  }
59
74
 
60
75
  return [[result, encode(value, options)].join(options.arrayFormatSeparator)];
61
76
  };
77
+ }
62
78
 
63
79
  default:
64
80
  return key => (result, value) => {
@@ -129,6 +145,28 @@ function parserForArrayFormat(options) {
129
145
  accumulator[key] = newValue;
130
146
  };
131
147
 
148
+ case 'bracket-separator':
149
+ return (key, value, accumulator) => {
150
+ const isArray = /(\[\])$/.test(key);
151
+ key = key.replace(/\[\]$/, '');
152
+
153
+ if (!isArray) {
154
+ accumulator[key] = value ? decode(value, options) : value;
155
+ return;
156
+ }
157
+
158
+ const arrayValue = value === null ?
159
+ [] :
160
+ value.split(options.arrayFormatSeparator).map(item => decode(item, options));
161
+
162
+ if (accumulator[key] === undefined) {
163
+ accumulator[key] = arrayValue;
164
+ return;
165
+ }
166
+
167
+ accumulator[key] = [].concat(accumulator[key], arrayValue);
168
+ };
169
+
132
170
  default:
133
171
  return (key, value, accumulator) => {
134
172
  if (accumulator[key] === undefined) {
@@ -244,11 +282,15 @@ function parse(query, options) {
244
282
  }
245
283
 
246
284
  for (const param of query.split('&')) {
285
+ if (param === '') {
286
+ continue;
287
+ }
288
+
247
289
  let [key, value] = splitOnFirst(options.decode ? param.replace(/\+/g, ' ') : param, '=');
248
290
 
249
291
  // Missing `=` should be `null`:
250
292
  // http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters
251
- value = value === undefined ? null : ['comma', 'separator'].includes(options.arrayFormat) ? value : decode(value, options);
293
+ value = value === undefined ? null : ['comma', 'separator', 'bracket-separator'].includes(options.arrayFormat) ? value : decode(value, options);
252
294
  formatter(decode(key, options), value, ret);
253
295
  }
254
296
 
@@ -330,6 +372,10 @@ exports.stringify = (object, options) => {
330
372
  }
331
373
 
332
374
  if (Array.isArray(value)) {
375
+ if (value.length === 0 && options.arrayFormat === 'bracket-separator') {
376
+ return encode(key, options) + '[]';
377
+ }
378
+
333
379
  return value
334
380
  .reduce(formatter(key), [])
335
381
  .join('&');
@@ -358,7 +404,8 @@ exports.parseUrl = (url, options) => {
358
404
  exports.stringifyUrl = (object, options) => {
359
405
  options = Object.assign({
360
406
  encode: true,
361
- strict: true
407
+ strict: true,
408
+ [encodeFragmentIdentifier]: true
362
409
  }, options);
363
410
 
364
411
  const url = removeHash(object.url).split('?')[0] || '';
@@ -373,8 +420,28 @@ exports.stringifyUrl = (object, options) => {
373
420
 
374
421
  let hash = getHash(object.url);
375
422
  if (object.fragmentIdentifier) {
376
- hash = `#${encode(object.fragmentIdentifier, options)}`;
423
+ hash = `#${options[encodeFragmentIdentifier] ? encode(object.fragmentIdentifier, options) : object.fragmentIdentifier}`;
377
424
  }
378
425
 
379
426
  return `${url}${queryString}${hash}`;
380
427
  };
428
+
429
+ exports.pick = (input, filter, options) => {
430
+ options = Object.assign({
431
+ parseFragmentIdentifier: true,
432
+ [encodeFragmentIdentifier]: false
433
+ }, options);
434
+
435
+ const {url, query, fragmentIdentifier} = exports.parseUrl(input, options);
436
+ return exports.stringifyUrl({
437
+ url,
438
+ query: filterObject(query, filter),
439
+ fragmentIdentifier
440
+ }, options);
441
+ };
442
+
443
+ exports.exclude = (input, filter, options) => {
444
+ const exclusionFilter = Array.isArray(filter) ? key => !filter.includes(key) : (key, value) => !filter(key, value);
445
+
446
+ return exports.pick(input, exclusionFilter, options);
447
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "query-string",
3
- "version": "6.13.8",
3
+ "version": "7.0.1",
4
4
  "description": "Parse and stringify URL query strings",
5
5
  "license": "MIT",
6
6
  "repository": "sindresorhus/query-string",
@@ -34,10 +34,12 @@
34
34
  "stringify",
35
35
  "encode",
36
36
  "decode",
37
- "searchparams"
37
+ "searchparams",
38
+ "filter"
38
39
  ],
39
40
  "dependencies": {
40
41
  "decode-uri-component": "^0.2.0",
42
+ "filter-obj": "^1.1.0",
41
43
  "split-on-first": "^1.0.0",
42
44
  "strict-uri-encode": "^2.0.0"
43
45
  },
package/readme.md CHANGED
@@ -1,4 +1,4 @@
1
- # query-string [![Build Status](https://travis-ci.com/sindresorhus/query-string.svg?branch=master)](https://travis-ci.com/github/sindresorhus/query-string) [![](https://badgen.net/bundlephobia/minzip/query-string)](https://bundlephobia.com/result?p=query-string)
1
+ # query-string
2
2
 
3
3
  > Parse and stringify URL [query strings](https://en.wikipedia.org/wiki/Query_string)
4
4
 
@@ -16,8 +16,41 @@
16
16
  <sup>Special thanks to:</sup>
17
17
  <br>
18
18
  <br>
19
- <a href="https://standardresume.co">
20
- <img src="https://sindresorhus.com/assets/thanks/standard-resume-logo.svg" width="200"/>
19
+ <a href="https://standardresume.co/tech">
20
+ <img src="https://sindresorhus.com/assets/thanks/standard-resume-logo.svg" width="180"/>
21
+ </a>
22
+ <br>
23
+ <br>
24
+ <br>
25
+ <a href="https://doppler.com/?utm_campaign=github_repo&utm_medium=referral&utm_content=query-string&utm_source=github">
26
+ <div>
27
+ <img src="https://dashboard.doppler.com/imgs/logo-long.svg" width="240" alt="Doppler">
28
+ </div>
29
+ <b>All your environment variables, in one place</b>
30
+ <div>
31
+ <span>Stop struggling with scattered API keys, hacking together home-brewed tools,</span>
32
+ <br>
33
+ <span>and avoiding access controls. Keep your team and servers in sync with Doppler.</span>
34
+ </div>
35
+ </a>
36
+ <br>
37
+ <a href="https://strapi.io/?ref=sindresorhus">
38
+ <div>
39
+ <img src="https://sindresorhus.com/assets/thanks/strapi-logo-white-bg.png" width="200" alt="Strapi">
40
+ </div>
41
+ <b>Strapi is the leading open-source headless CMS.</b>
42
+ <div>
43
+ <sup>It’s 100% JavaScript, fully customizable, and developer-first.</sup>
44
+ </div>
45
+ </a>
46
+ <br>
47
+ <a href="https://oss.capital">
48
+ <div>
49
+ <img src="https://sindresorhus.com/assets/thanks/oss-capital-logo-white-bg.svg" width="300" alt="OSS Capital">
50
+ </div>
51
+ <div>
52
+ <sup><b>Founded in 2018, OSS Capital is the first and only venture capital platform focused<br>exclusively on supporting early-stage COSS (commercial open source) startup founders.</b></sup>
53
+ </div>
21
54
  </a>
22
55
  </p>
23
56
  </div>
@@ -32,7 +65,9 @@
32
65
  $ npm install query-string
33
66
  ```
34
67
 
35
- This module targets Node.js 6 or later and the latest version of Chrome, Firefox, and Safari. If you want support for older browsers, or, if your project is using create-react-app v1, use version 5: `npm install query-string@5`.
68
+ **Not `npm install querystring`!!!!!**
69
+
70
+ This module targets Node.js 6 or later and the latest version of Chrome, Firefox, and Safari.
36
71
 
37
72
  ## Usage
38
73
 
@@ -125,6 +160,30 @@ queryString.parse('foo=1|2|3', {arrayFormat: 'separator', arrayFormatSeparator:
125
160
  //=> {foo: ['1', '2', '3']}
126
161
  ```
127
162
 
163
+ - `'bracket-separator'`: Parse arrays (that are explicitly marked with brackets) with elements separated by a custom character:
164
+
165
+ ```js
166
+ const queryString = require('query-string');
167
+
168
+ queryString.parse('foo[]', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
169
+ //=> {foo: []}
170
+
171
+ queryString.parse('foo[]=', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
172
+ //=> {foo: ['']}
173
+
174
+ queryString.parse('foo[]=1', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
175
+ //=> {foo: ['1']}
176
+
177
+ queryString.parse('foo[]=1|2|3', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
178
+ //=> {foo: ['1', '2', '3']}
179
+
180
+ queryString.parse('foo[]=1||3|||6', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
181
+ //=> {foo: ['1', '', 3, '', '', '6']}
182
+
183
+ queryString.parse('foo[]=1|2|3&bar=fluffy&baz[]=4', {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
184
+ //=> {foo: ['1', '2', '3'], bar: 'fluffy', baz:['4']}
185
+ ```
186
+
128
187
  - `'none'`: Parse arrays with elements using duplicate keys:
129
188
 
130
189
  ```js
@@ -228,6 +287,47 @@ const queryString = require('query-string');
228
287
 
229
288
  queryString.stringify({foo: [1, 2, 3]}, {arrayFormat: 'comma'});
230
289
  //=> 'foo=1,2,3'
290
+
291
+ queryString.stringify({foo: [1, null, '']}, {arrayFormat: 'comma'});
292
+ //=> 'foo=1,,'
293
+ // Note that typing information for null values is lost
294
+ // and `.parse('foo=1,,')` would return `{foo: [1, '', '']}`.
295
+ ```
296
+
297
+ - `'separator'`: Serialize arrays by separating elements with a custom character:
298
+
299
+ ```js
300
+ const queryString = require('query-string');
301
+
302
+ queryString.stringify({foo: [1, 2, 3]}, {arrayFormat: 'separator', arrayFormatSeparator: '|'});
303
+ //=> 'foo=1|2|3'
304
+ ```
305
+
306
+ - `'bracket-separator'`: Serialize arrays by explicitly post-fixing array names with brackets and separating elements with a custom character:
307
+
308
+ ```js
309
+ const queryString = require('query-string');
310
+
311
+ queryString.stringify({foo: []}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
312
+ //=> 'foo[]'
313
+
314
+ queryString.stringify({foo: ['']}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
315
+ //=> 'foo[]='
316
+
317
+ queryString.stringify({foo: [1]}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
318
+ //=> 'foo[]=1'
319
+
320
+ queryString.stringify({foo: [1, 2, 3]}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
321
+ //=> 'foo[]=1|2|3'
322
+
323
+ queryString.stringify({foo: [1, '', 3, null, null, 6]}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
324
+ //=> 'foo[]=1||3|||6'
325
+
326
+ queryString.stringify({foo: [1, '', 3, null, null, 6]}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|', skipNull: true});
327
+ //=> 'foo[]=1||3|6'
328
+
329
+ queryString.stringify({foo: [1, 2, 3], bar: 'fluffy', baz: [4]}, {arrayFormat: 'bracket-separator', arrayFormatSeparator: '|'});
330
+ //=> 'foo[]=1|2|3&bar=fluffy&baz[]=4'
231
331
  ```
232
332
 
233
333
  - `'none'`: Serialize arrays by using duplicate keys:
@@ -415,6 +515,64 @@ Type: `object`
415
515
 
416
516
  Query items to add to the URL.
417
517
 
518
+ ### .pick(url, keys, options?)
519
+ ### .pick(url, filter, options?)
520
+
521
+ Pick query parameters from a URL.
522
+
523
+ Returns a string with the new URL.
524
+
525
+ ```js
526
+ const queryString = require('query-string');
527
+
528
+ queryString.pick('https://foo.bar?foo=1&bar=2#hello', ['foo']);
529
+ //=> 'https://foo.bar?foo=1#hello'
530
+
531
+ queryString.pick('https://foo.bar?foo=1&bar=2#hello', (name, value) => value === 2, {parseNumbers: true});
532
+ //=> 'https://foo.bar?bar=2#hello'
533
+ ```
534
+
535
+ ### .exclude(url, keys, options?)
536
+ ### .exclude(url, filter, options?)
537
+
538
+ Exclude query parameters from a URL.
539
+
540
+ Returns a string with the new URL.
541
+
542
+ ```js
543
+ const queryString = require('query-string');
544
+
545
+ queryString.exclude('https://foo.bar?foo=1&bar=2#hello', ['foo']);
546
+ //=> 'https://foo.bar?bar=2#hello'
547
+
548
+ queryString.exclude('https://foo.bar?foo=1&bar=2#hello', (name, value) => value === 2, {parseNumbers: true});
549
+ //=> 'https://foo.bar?foo=1#hello'
550
+ ```
551
+
552
+ #### url
553
+
554
+ Type: `string`
555
+
556
+ The URL containing the query parameters to filter.
557
+
558
+ #### keys
559
+
560
+ Type: `string[]`
561
+
562
+ The names of the query parameters to filter based on the function used.
563
+
564
+ #### filter
565
+
566
+ Type: `(key, value) => boolean`
567
+
568
+ A filter predicate that will be provided the name of each query parameter and its value. The `parseNumbers` and `parseBooleans` options also affect `value`.
569
+
570
+ #### options
571
+
572
+ Type: `object`
573
+
574
+ [Parse options](#options) and [stringify options](#options-1).
575
+
418
576
  ## Nesting
419
577
 
420
578
  This module intentionally doesn't support nesting as it's not spec'd and varies between implementations, which causes a lot of [edge cases](https://github.com/visionmedia/node-querystring/issues).
@@ -462,6 +620,12 @@ queryString.stringify({foo: undefined});
462
620
  //=> ''
463
621
  ```
464
622
 
623
+ ## FAQ
624
+
625
+ ### Why is it parsing `+` as a space?
626
+
627
+ See [this answer](https://github.com/sindresorhus/query-string/issues/305).
628
+
465
629
  ## query-string for enterprise
466
630
 
467
631
  Available as part of the Tidelift Subscription.