Repository: sindresorhus/normalize-url (js)

Issue:
Exactly 2 forward slashes between the host+port & path is not normalizing to 1 forward slash

You can see it by adding the following test cases:

```
t.is(normalizeUrl('http://sindresorhus.com:5000///foo'), 'http://sindresorhus.com:5000/foo'); // passes
t.is(normalizeUrl('http://sindresorhus.com///foo'), 'http://sindresorhus.com/foo'); // passes
t.is(normalizeUrl('http://sindresorhus.com:5000//foo'), 'http://sindresorhus.com:5000/foo'); // fails - http://sindresorhus.com:5000//foo
t.is(normalizeUrl('http://sindresorhus.com//foo'), 'http://sindresorhus.com/foo'); // fails - http://sindresorhus.com//foo
```

Pull request description:
Removing multiple slashes if they are at the start of pathname
While upgrading normalize-url from 3.1.0 to 4, I noticed that removal of duplicate slashes started to fail in our project. The added tests demonstrate the issue.

---

Fixes #76 

Patch:
diff --git a/index.js b/index.js
index 7e9e294..f0c868b 100644
--- a/index.js
+++ b/index.js
@@ -74,7 +74,7 @@ module.exports = (urlString, options) => {
 	if (urlObj.pathname) {
 		// TODO: Use the following instead when targeting Node.js 10
 		// `urlObj.pathname = urlObj.pathname.replace(/(?<!https?:)\/{2,}/g, '/');`
-		urlObj.pathname = urlObj.pathname.replace(/((?![https?:]).)\/{2,}/g, (_, p1) => {
+		urlObj.pathname = urlObj.pathname.replace(/((?!:).|^)\/{2,}/g, (_, p1) => {
 			if (/^(?!\/)/g.test(p1)) {
 				return `${p1}/`;
 			}
@@ -129,11 +129,15 @@ module.exports = (urlString, options) => {
 		urlObj.searchParams.sort();
 	}
 
+	if (options.removeTrailingSlash) {
+		urlObj.pathname = urlObj.pathname.replace(/\/$/, '');
+	}
+
 	// Take advantage of many of the Node `url` normalizations
 	urlString = urlObj.toString();
 
 	// Remove ending `/`
-	if (options.removeTrailingSlash || urlObj.pathname === '/') {
+	if ((options.removeTrailingSlash || urlObj.pathname === '/') && urlObj.hash === '') {
 		urlString = urlString.replace(/\/$/, '');
 	}
 


Test patch:
diff --git a/test.js b/test.js
index 9333d35..d7c09c6 100644
--- a/test.js
+++ b/test.js
@@ -31,6 +31,11 @@ test('main', t => {
 	t.is(normalizeUrl('http://sindresorhus.com////foo/bar'), 'http://sindresorhus.com/foo/bar');
 	t.is(normalizeUrl('http://sindresorhus.com////foo////bar'), 'http://sindresorhus.com/foo/bar');
 	t.is(normalizeUrl('//sindresorhus.com/', {normalizeProtocol: false}), '//sindresorhus.com');
+	t.is(normalizeUrl('//sindresorhus.com//foo', {normalizeProtocol: false}), '//sindresorhus.com/foo');
+	t.is(normalizeUrl('http://sindresorhus.com:5000///foo'), 'http://sindresorhus.com:5000/foo');
+	t.is(normalizeUrl('http://sindresorhus.com///foo'), 'http://sindresorhus.com/foo');
+	t.is(normalizeUrl('http://sindresorhus.com:5000//foo'), 'http://sindresorhus.com:5000/foo');
+	t.is(normalizeUrl('http://sindresorhus.com//foo'), 'http://sindresorhus.com/foo');
 	t.is(normalizeUrl('//sindresorhus.com:80/', {normalizeProtocol: false}), '//sindresorhus.com');
 	t.is(normalizeUrl('http://sindresorhus.com/foo#bar'), 'http://sindresorhus.com/foo#bar');
 	t.is(normalizeUrl('http://sindresorhus.com/foo#bar', {stripHash: true}), 'http://sindresorhus.com/foo');
@@ -115,6 +120,7 @@ test('removeTrailingSlash option', t => {
 	t.is(normalizeUrl('http://sindresorhus.com/', options), 'http://sindresorhus.com');
 	t.is(normalizeUrl('http://sindresorhus.com/redirect/'), 'http://sindresorhus.com/redirect');
 	t.is(normalizeUrl('http://sindresorhus.com/redirect/', options), 'http://sindresorhus.com/redirect/');
+	t.is(normalizeUrl('http://sindresorhus.com/#/', options), 'http://sindresorhus.com/#/');
 });
 
 test('removeDirectoryIndex option', t => {
@@ -151,6 +157,8 @@ test('removeTrailingSlash and removeDirectoryIndex options)', t => {
 	};
 	t.is(normalizeUrl('http://sindresorhus.com/path/', options1), 'http://sindresorhus.com/path');
 	t.is(normalizeUrl('http://sindresorhus.com/path/index.html', options1), 'http://sindresorhus.com/path');
+	t.is(normalizeUrl('http://sindresorhus.com/#/path/', options1), 'http://sindresorhus.com/#/path/');
+	t.is(normalizeUrl('http://sindresorhus.com/foo/#/bar/', options1), 'http://sindresorhus.com/foo#/bar/');
 
 	const options2 = {
 		removeTrailingSlash: false,
@@ -158,6 +166,7 @@ test('removeTrailingSlash and removeDirectoryIndex options)', t => {
 	};
 	t.is(normalizeUrl('http://sindresorhus.com/path/', options2), 'http://sindresorhus.com/path/');
 	t.is(normalizeUrl('http://sindresorhus.com/path/index.html', options2), 'http://sindresorhus.com/path/');
+	t.is(normalizeUrl('http://sindresorhus.com/#/path/', options2), 'http://sindresorhus.com/#/path/');
 });
 
 test('sortQueryParameters option', t => {