query-string 6.11.1 → 6.13.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.
package/index.d.ts CHANGED
@@ -121,6 +121,21 @@ export interface ParseOptions {
121
121
  ```
122
122
  */
123
123
  readonly parseBooleans?: boolean;
124
+
125
+ /**
126
+ Parse the fragment identifier from the URL and add it to result object.
127
+
128
+ @default false
129
+
130
+ @example
131
+ ```
132
+ import queryString = require('query-string');
133
+
134
+ queryString.parseUrl('https://foo.bar?foo=bar#xyz', {parseFragmentIdentifier: true});
135
+ //=> {url: 'https://foo.bar', query: {foo: 'bar'}, fragmentIdentifier: 'xyz'}
136
+ ```
137
+ */
138
+ readonly parseFragmentIdentifier?: boolean;
124
139
  }
125
140
 
126
141
  export interface ParsedQuery<T = string> {
@@ -142,11 +157,20 @@ export function parse(query: string, options?: ParseOptions): ParsedQuery;
142
157
  export interface ParsedUrl {
143
158
  readonly url: string;
144
159
  readonly query: ParsedQuery;
160
+
161
+ /**
162
+ The fragment identifier of the URL.
163
+
164
+ Present when the `parseFragmentIdentifier` option is `true`.
165
+ */
166
+ readonly fragmentIdentifier?: string;
145
167
  }
146
168
 
147
169
  /**
148
170
  Extract the URL and the query string as an object.
149
171
 
172
+ If the `parseFragmentIdentifier` option is `true`, the object will also contain a `fragmentIdentifier` property.
173
+
150
174
  @param url - The URL to parse.
151
175
 
152
176
  @example
@@ -155,6 +179,9 @@ import queryString = require('query-string');
155
179
 
156
180
  queryString.parseUrl('https://foo.bar?foo=bar');
157
181
  //=> {url: 'https://foo.bar', query: {foo: 'bar'}}
182
+
183
+ queryString.parseUrl('https://foo.bar?foo=bar#xyz', {parseFragmentIdentifier: true});
184
+ //=> {url: 'https://foo.bar', query: {foo: 'bar'}, fragmentIdentifier: 'xyz'}
158
185
  ```
159
186
  */
160
187
  export function parseUrl(url: string, options?: ParseOptions): ParsedUrl;
@@ -283,6 +310,33 @@ export interface StringifyOptions {
283
310
  ```
284
311
  */
285
312
  readonly skipNull?: boolean;
313
+
314
+ /**
315
+ Skip keys with an empty string as the value.
316
+
317
+ @default false
318
+
319
+ @example
320
+ ```
321
+ import queryString = require('query-string');
322
+
323
+ queryString.stringify({a: 1, b: '', c: '', d: 4}, {
324
+ skipEmptyString: true
325
+ });
326
+ //=> 'a=1&d=4'
327
+ ```
328
+
329
+ @example
330
+ ```
331
+ import queryString = require('query-string');
332
+
333
+ queryString.stringify({a: '', b: ''}, {
334
+ skipEmptyString: true
335
+ });
336
+ //=> ''
337
+ ```
338
+ */
339
+ readonly skipEmptyString?: boolean;
286
340
  }
287
341
 
288
342
  /**
@@ -305,6 +359,8 @@ Stringify an object into a URL with a query string and sorting the keys. The inv
305
359
 
306
360
  Query items in the `query` property overrides queries in the `url` property.
307
361
 
362
+ The `fragmentIdentifier` property overrides the fragment identifier in the `url` property.
363
+
308
364
  @example
309
365
  ```
310
366
  queryString.stringifyUrl({url: 'https://foo.bar', query: {foo: 'bar'}});
@@ -312,6 +368,15 @@ queryString.stringifyUrl({url: 'https://foo.bar', query: {foo: 'bar'}});
312
368
 
313
369
  queryString.stringifyUrl({url: 'https://foo.bar?foo=baz', query: {foo: 'bar'}});
314
370
  //=> 'https://foo.bar?foo=bar'
371
+
372
+ queryString.stringifyUrl({
373
+ url: 'https://foo.bar',
374
+ query: {
375
+ top: 'foo'
376
+ },
377
+ fragmentIdentifier: 'bar'
378
+ });
379
+ //=> 'https://foo.bar?top=foo#bar'
315
380
  ```
316
381
  */
317
382
  export function stringifyUrl(
package/index.js CHANGED
@@ -3,12 +3,19 @@ const strictUriEncode = require('strict-uri-encode');
3
3
  const decodeComponent = require('decode-uri-component');
4
4
  const splitOnFirst = require('split-on-first');
5
5
 
6
+ const isNullOrUndefined = value => value === null || value === undefined;
7
+
6
8
  function encoderForArrayFormat(options) {
7
9
  switch (options.arrayFormat) {
8
10
  case 'index':
9
11
  return key => (result, value) => {
10
12
  const index = result.length;
11
- if (value === undefined || (options.skipNull && value === null)) {
13
+
14
+ if (
15
+ value === undefined ||
16
+ (options.skipNull && value === null) ||
17
+ (options.skipEmptyString && value === '')
18
+ ) {
12
19
  return result;
13
20
  }
14
21
 
@@ -24,7 +31,11 @@ function encoderForArrayFormat(options) {
24
31
 
25
32
  case 'bracket':
26
33
  return key => (result, value) => {
27
- if (value === undefined || (options.skipNull && value === null)) {
34
+ if (
35
+ value === undefined ||
36
+ (options.skipNull && value === null) ||
37
+ (options.skipEmptyString && value === '')
38
+ ) {
28
39
  return result;
29
40
  }
30
41
 
@@ -51,7 +62,11 @@ function encoderForArrayFormat(options) {
51
62
 
52
63
  default:
53
64
  return key => (result, value) => {
54
- if (value === undefined || (options.skipNull && value === null)) {
65
+ if (
66
+ value === undefined ||
67
+ (options.skipNull && value === null) ||
68
+ (options.skipEmptyString && value === '')
69
+ ) {
55
70
  return result;
56
71
  }
57
72
 
@@ -231,7 +246,7 @@ function parse(input, options) {
231
246
 
232
247
  // Missing `=` should be `null`:
233
248
  // http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters
234
- value = value === undefined ? null : options.arrayFormat === 'comma' ? value : decode(value, options);
249
+ value = value === undefined ? null : ['comma', 'separator'].includes(options.arrayFormat) ? value : decode(value, options);
235
250
  formatter(decode(key, options), value, ret);
236
251
  }
237
252
 
@@ -280,14 +295,18 @@ exports.stringify = (object, options) => {
280
295
 
281
296
  validateArrayFormatSeparator(options.arrayFormatSeparator);
282
297
 
298
+ const shouldFilter = key => (
299
+ (options.skipNull && isNullOrUndefined(object[key])) ||
300
+ (options.skipEmptyString && object[key] === '')
301
+ );
302
+
283
303
  const formatter = encoderForArrayFormat(options);
284
304
 
285
- const objectCopy = Object.assign({}, object);
286
- if (options.skipNull) {
287
- for (const key of Object.keys(objectCopy)) {
288
- if (objectCopy[key] === undefined || objectCopy[key] === null) {
289
- delete objectCopy[key];
290
- }
305
+ const objectCopy = {};
306
+
307
+ for (const key of Object.keys(object)) {
308
+ if (!shouldFilter(key)) {
309
+ objectCopy[key] = object[key];
291
310
  }
292
311
  }
293
312
 
@@ -319,22 +338,41 @@ exports.stringify = (object, options) => {
319
338
  };
320
339
 
321
340
  exports.parseUrl = (input, options) => {
322
- return {
323
- url: removeHash(input).split('?')[0] || '',
324
- query: parse(extract(input), options)
325
- };
341
+ options = Object.assign({
342
+ decode: true
343
+ }, options);
344
+
345
+ const [url, hash] = splitOnFirst(input, '#');
346
+
347
+ return Object.assign(
348
+ {
349
+ url: url.split('?')[0] || '',
350
+ query: parse(extract(input), options)
351
+ },
352
+ options && options.parseFragmentIdentifier && hash ? {fragmentIdentifier: decode(hash, options)} : {}
353
+ );
326
354
  };
327
355
 
328
356
  exports.stringifyUrl = (input, options) => {
357
+ options = Object.assign({
358
+ encode: true,
359
+ strict: true
360
+ }, options);
361
+
329
362
  const url = removeHash(input.url).split('?')[0] || '';
330
363
  const queryFromUrl = exports.extract(input.url);
331
- const parsedQueryFromUrl = exports.parse(queryFromUrl);
332
- const hash = getHash(input.url);
364
+ const parsedQueryFromUrl = exports.parse(queryFromUrl, {sort: false});
365
+
333
366
  const query = Object.assign(parsedQueryFromUrl, input.query);
334
367
  let queryString = exports.stringify(query, options);
335
368
  if (queryString) {
336
369
  queryString = `?${queryString}`;
337
370
  }
338
371
 
372
+ let hash = getHash(input.url);
373
+ if (input.fragmentIdentifier) {
374
+ hash = `#${encode(input.fragmentIdentifier, options)}`;
375
+ }
376
+
339
377
  return `${url}${queryString}${hash}`;
340
378
  };
package/license CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
3
+ Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (http://sindresorhus.com)
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
6
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "query-string",
3
- "version": "6.11.1",
3
+ "version": "6.13.1",
4
4
  "description": "Parse and stringify URL query strings",
5
5
  "license": "MIT",
6
6
  "repository": "sindresorhus/query-string",
@@ -8,12 +8,13 @@
8
8
  "author": {
9
9
  "name": "Sindre Sorhus",
10
10
  "email": "sindresorhus@gmail.com",
11
- "url": "sindresorhus.com"
11
+ "url": "https://sindresorhus.com"
12
12
  },
13
13
  "engines": {
14
14
  "node": ">=6"
15
15
  },
16
16
  "scripts": {
17
+ "benchmark": "node benchmark.js",
17
18
  "test": "xo && ava && tsd"
18
19
  },
19
20
  "files": [
@@ -36,12 +37,13 @@
36
37
  "searchparams"
37
38
  ],
38
39
  "dependencies": {
39
- "split-on-first": "^1.0.0",
40
40
  "decode-uri-component": "^0.2.0",
41
+ "split-on-first": "^1.0.0",
41
42
  "strict-uri-encode": "^2.0.0"
42
43
  },
43
44
  "devDependencies": {
44
45
  "ava": "^1.4.1",
46
+ "benchmark": "^2.1.4",
45
47
  "deep-equal": "^1.0.1",
46
48
  "fast-check": "^1.5.0",
47
49
  "tsd": "^0.7.3",
package/readme.md CHANGED
@@ -1,4 +1,4 @@
1
- # query-string [![Build Status](https://travis-ci.org/sindresorhus/query-string.svg?branch=master)](https://travis-ci.org/sindresorhus/query-string)
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)
2
2
 
3
3
  > Parse and stringify URL [query strings](https://en.wikipedia.org/wiki/Query_string)
4
4
 
@@ -16,14 +16,9 @@
16
16
  <sup>Special thanks to:</sup>
17
17
  <br>
18
18
  <br>
19
- <a href="https://github.com/botpress/botpress">
20
- <img src="https://sindresorhus.com/assets/thanks/botpress-logo.svg" width="260" alt="Botpress">
19
+ <a href="https://standardresume.co">
20
+ <img src="https://sindresorhus.com/assets/thanks/standard-resume-logo.svg" width="200"/>
21
21
  </a>
22
- <br>
23
- <sub><b>Botpress is an open-source conversational assistant creation platform.</b></sub>
24
- <br>
25
- <sub>They <a href="https://github.com/botpress/botpress/blob/master/.github/CONTRIBUTING.md">welcome contributions</a> from anyone, whether you're into machine learning,<br>want to get started in open-source, or just have an improvement idea.</sub>
26
- <br>
27
22
  </p>
28
23
  </div>
29
24
 
@@ -304,6 +299,31 @@ queryString.stringify({a: undefined, b: null}, {
304
299
  //=> ''
305
300
  ```
306
301
 
302
+ ##### skipEmptyString
303
+
304
+ Skip keys with an empty string as the value.
305
+
306
+ Type: `boolean`\
307
+ Default: `false`
308
+
309
+ ```js
310
+ const queryString = require('query-string');
311
+
312
+ queryString.stringify({a: 1, b: '', c: '', d: 4}, {
313
+ skipEmptyString: true
314
+ });
315
+ //=> 'a=1&d=4'
316
+ ```
317
+
318
+ ```js
319
+ const queryString = require('query-string');
320
+
321
+ queryString.stringify({a: '', b: ''}, {
322
+ skipEmptyString: true
323
+ });
324
+ //=> ''
325
+ ```
326
+
307
327
  ### .extract(string)
308
328
 
309
329
  Extract a query string from a URL that can be passed into `.parse()`.
@@ -314,15 +334,40 @@ Note: This behaviour can be changed with the `skipNull` option.
314
334
 
315
335
  Extract the URL and the query string as an object.
316
336
 
317
- The `options` are the same as for `.parse()`.
318
-
319
337
  Returns an object with a `url` and `query` property.
320
338
 
339
+ If the `parseFragmentIdentifier` option is `true`, the object will also contain a `fragmentIdentifier` property.
340
+
321
341
  ```js
322
342
  const queryString = require('query-string');
323
343
 
324
344
  queryString.parseUrl('https://foo.bar?foo=bar');
325
345
  //=> {url: 'https://foo.bar', query: {foo: 'bar'}}
346
+
347
+ queryString.parseUrl('https://foo.bar?foo=bar#xyz', {parseFragmentIdentifier: true});
348
+ //=> {url: 'https://foo.bar', query: {foo: 'bar'}, fragmentIdentifier: 'xyz'}
349
+ ```
350
+
351
+ #### options
352
+
353
+ Type: `object`
354
+
355
+ The options are the same as for `.parse()`.
356
+
357
+ Extra options are as below.
358
+
359
+ ##### parseFragmentIdentifier
360
+
361
+ Parse the fragment identifier from the URL.
362
+
363
+ Type: `boolean`\
364
+ Default: `false`
365
+
366
+ ```js
367
+ const queryString = require('query-string');
368
+
369
+ queryString.parseUrl('https://foo.bar?foo=bar#xyz', {parseFragmentIdentifier: true});
370
+ //=> {url: 'https://foo.bar', query: {foo: 'bar'}, fragmentIdentifier: 'xyz'}
326
371
  ```
327
372
 
328
373
  ### .stringifyUrl(object, options?)
@@ -335,12 +380,23 @@ Returns a string with the URL and a query string.
335
380
 
336
381
  Query items in the `query` property overrides queries in the `url` property.
337
382
 
383
+ The `fragmentIdentifier` property overrides the fragment identifier in the `url` property.
384
+
338
385
  ```js
339
386
  queryString.stringifyUrl({url: 'https://foo.bar', query: {foo: 'bar'}});
340
387
  //=> 'https://foo.bar?foo=bar'
341
388
 
342
389
  queryString.stringifyUrl({url: 'https://foo.bar?foo=baz', query: {foo: 'bar'}});
343
390
  //=> 'https://foo.bar?foo=bar'
391
+
392
+ queryString.stringifyUrl({
393
+ url: 'https://foo.bar',
394
+ query: {
395
+ top: 'foo'
396
+ },
397
+ fragmentIdentifier: 'bar'
398
+ });
399
+ //=> 'https://foo.bar?top=foo#bar'
344
400
  ```
345
401
 
346
402
  #### object