Skip to content

Commit

Permalink
Add .stringifyUrl() method (#217)
Browse files Browse the repository at this point in the history
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
  • Loading branch information
komkanit and sindresorhus committed Jan 16, 2020
1 parent d7c4b89 commit 1604958
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 0 deletions.
19 changes: 19 additions & 0 deletions index.d.ts
Expand Up @@ -267,3 +267,22 @@ Extract a query string from a URL that can be passed into `.parse()`.
Note: This behaviour can be changed with the `skipNull` option.
*/
export function extract(url: string): string;

/**
Stringify an object into a URL with a query string and sorting the keys. The inverse of [`.parseUrl()`](https://github.com/sindresorhus/query-string#parseurlstring-options)
Query items in the `query` property overrides queries in the `url` property.
@example
```
queryString.stringifyUrl({url: 'https://foo.bar', query: {foo: 'bar'}});
//=> 'https://foo.bar?foo=bar'
queryString.stringifyUrl({url: 'https://foo.bar?foo=baz', query: {foo: 'bar'}});
//=> 'https://foo.bar?foo=bar'
```
*/
export function stringifyUrl(
object: ParsedUrl,
options?: StringifyOptions
): string;
24 changes: 24 additions & 0 deletions index.js
Expand Up @@ -161,6 +161,16 @@ function removeHash(input) {
return input;
}

function getHash(url) {
let hash = '';
const hashStart = url.indexOf('#');
if (hashStart !== -1) {
hash = url.slice(hashStart);
}

return hash;
}

function extract(input) {
input = removeHash(input);
const queryStart = input.indexOf('?');
Expand Down Expand Up @@ -300,3 +310,17 @@ exports.parseUrl = (input, options) => {
query: parse(extract(input), options)
};
};

exports.stringifyUrl = (input, options) => {
const url = removeHash(input.url).split('?')[0] || '';
const queryFromUrl = this.extract(input.url);
const parsedQueryFromUrl = this.parse(queryFromUrl);
const hash = getHash(input.url);
const query = Object.assign(parsedQueryFromUrl, input.query);
let queryString = this.stringify(query, options);
if (queryString) {
queryString = `?${queryString}`;
}

return `${url}${queryString}${hash}`;
};
33 changes: 33 additions & 0 deletions readme.md
Expand Up @@ -304,6 +304,39 @@ queryString.parseUrl('https://foo.bar?foo=bar');
//=> {url: 'https://foo.bar', query: {foo: 'bar'}}
```

### .stringifyUrl(object, options?)

Stringify an object into a URL with a query string and sorting the keys. The inverse of [`.parseUrl()`](https://github.com/sindresorhus/query-string#parseurlstring-options)

The `options` are the same as for `.stringify()`.

Returns a string with the URL and a query string.

Query items in the `query` property overrides queries in the `url` property.

```js
queryString.stringifyUrl({url: 'https://foo.bar', query: {foo: 'bar'}});
//=> 'https://foo.bar?foo=bar'

queryString.stringifyUrl({url: 'https://foo.bar?foo=baz', query: {foo: 'bar'}});
//=> 'https://foo.bar?foo=bar'
```

#### object

Type: `object`

##### url

Type: `string`

The URL to stringify.

##### query

Type: `object`

Query items to add to the URL.

## Nesting

Expand Down
38 changes: 38 additions & 0 deletions test/stringify-url.js
@@ -0,0 +1,38 @@
import test from 'ava';
import queryString from '..';

test('stringify URL without a query string', t => {
t.deepEqual(queryString.stringifyUrl({url: 'https://foo.bar/'}), 'https://foo.bar/');
t.deepEqual(queryString.stringifyUrl({url: 'https://foo.bar/', query: {}}), 'https://foo.bar/');
t.deepEqual(queryString.stringifyUrl({url: 'https://foo.bar/#top', query: {}}), 'https://foo.bar/#top');
t.deepEqual(queryString.stringifyUrl({url: '', query: {}}), '');
t.deepEqual(queryString.stringifyUrl({url: 'https://foo.bar?', query: {}}), 'https://foo.bar');
t.deepEqual(queryString.stringifyUrl({url: 'https://foo.bar?foo=bar', query: {}}), 'https://foo.bar?foo=bar');
});

test('stringify URL with a query string', t => {
t.deepEqual(queryString.stringifyUrl({url: 'https://foo.bar', query: {foo: 'bar'}}), 'https://foo.bar?foo=bar');
t.deepEqual(queryString.stringifyUrl({url: 'https://foo.bar?', query: {foo: 'bar'}}), 'https://foo.bar?foo=bar');
t.deepEqual(queryString.stringifyUrl({url: 'https://foo.bar/#top', query: {foo: 'bar'}}), 'https://foo.bar/?foo=bar#top');
t.deepEqual(queryString.stringifyUrl({url: 'https://foo.bar', query: {foo: 'bar', a: 'b'}}), 'https://foo.bar?a=b&foo=bar');
t.deepEqual(queryString.stringifyUrl({url: 'https://foo.bar?a=b', query: {foo: ['bar', 'baz']}}), 'https://foo.bar?a=b&foo=bar&foo=baz');
t.deepEqual(queryString.stringifyUrl({url: 'https://foo.bar?foo=baz', query: {foo: 'bar'}}), 'https://foo.bar?foo=bar');
});

test('stringify URL from the result of `parseUrl` without query string', t => {
const url = 'https://foo.bar';
const parsedUrl = queryString.parseUrl(url);
t.deepEqual(queryString.stringifyUrl(parsedUrl), url);
});

test('stringify URL from the result of `parseUrl` with query string', t => {
const url = 'https://foo.bar?foo=bar&foo=baz';
const parsedUrl = queryString.parseUrl(url);
t.deepEqual(queryString.stringifyUrl(parsedUrl), url);
});

test('stringify URL from the result of `parseUrl` with query string that contains `=`', t => {
const url = 'https://foo.bar?foo=bar=&foo=baz=';
const parsedUrl = queryString.parseUrl(url);
t.deepEqual(queryString.stringifyUrl(parsedUrl, {encode: false}), url);
});

0 comments on commit 1604958

Please sign in to comment.