Repository: sindresorhus/normalize-url (js)

Issue:
Regex for removal of duplicate slashes not preceded by a protocol is too strict
```js
// Remove duplicate slashes if not preceded by a protocol
if (urlObj.pathname) {
  urlObj.pathname = urlObj.pathname.replace(/(?<!https?:)\/{2,}/g, '/');
}
```

Limiting the preceding protocol to only http or https is too strict. There are valid URLs that contain other protocols (ftp, s3, git, etc) as part of their path that are rendered invalid by this regex. 

Example URLs broken by this regex:
* `http://sindresorhus.com/s3://sindresorhus.com` becomes `http://sindresorhus.com/s3:/sindresorhus.com`
* `http://sindresorhus.com/git://sindresorhus.com` becomes `http://sindresorhus.com/git:/sindresorhus.com`

Real world URL broken by this regex:
* https://images.megaphone.fm/8wdeoO3TExq3DnwqQWKXcWfnnGOJkA9kzcaZKo3Ue0M/plain/s3://megaphone-prod/podcasts/daef779e-0f93-11e9-8be1-ef6a540ab876/image/uploads_2F1561781562946-7xoryiijhz6-d6e84acd3033beaa78167923137f8d6c_2FEar_Biscuits_Profile_2019.jpg becomes https://images.megaphone.fm/8wdeoO3TExq3DnwqQWKXcWfnnGOJkA9kzcaZKo3Ue0M/plain/s3:/megaphone-prod/podcasts/daef779e-0f93-11e9-8be1-ef6a540ab876/image/uploads_2F1561781562946-7xoryiijhz6-d6e84acd3033beaa78167923137f8d6c_2FEar_Biscuits_Profile_2019.jpg


Pull request:
Allow any protocol in the duplicate slashes normalization
Fixes #114 

Prior to this, duplicate slashes would be removed unless preceded by "http" or "https" protocols. This was too strict.

The regex was updated to allow for any 2+ character alphanumeric protocol. Went with requiring at least 2 characters since every scheme listed here (https://en.wikipedia.org/wiki/List_of_URI_schemes) is at least 2 characters.

Patch:
diff --git a/index.js b/index.js
index 4bf5823..f7fc2e6 100644
--- a/index.js
+++ b/index.js
@@ -117,7 +117,7 @@ const normalizeUrl = (urlString, options) => {
 
 	// Remove duplicate slashes if not preceded by a protocol
 	if (urlObj.pathname) {
-		urlObj.pathname = urlObj.pathname.replace(/(?<!https?:)\/{2,}/g, '/');
+		urlObj.pathname = urlObj.pathname.replace(/(?<!\b(?:[a-z][a-z\d+\-.]{1,50}:))\/{2,}/g, '/');
 	}
 
 	// Decode URI octets


Test patch:
diff --git a/test.js b/test.js
index cdd1e02..4165f9a 100644
--- a/test.js
+++ b/test.js
@@ -205,6 +205,18 @@ test('remove duplicate pathname slashes', t => {
 	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('http://sindresorhus.com/s3://sindresorhus.com'), 'http://sindresorhus.com/s3://sindresorhus.com');
+	t.is(normalizeUrl('http://sindresorhus.com/s3://sindresorhus.com//foo'), 'http://sindresorhus.com/s3://sindresorhus.com/foo');
+	t.is(normalizeUrl('http://sindresorhus.com//foo/s3://sindresorhus.com'), 'http://sindresorhus.com/foo/s3://sindresorhus.com');
+	t.is(normalizeUrl('http://sindresorhus.com/git://sindresorhus.com'), 'http://sindresorhus.com/git://sindresorhus.com');
+	t.is(normalizeUrl('http://sindresorhus.com/git://sindresorhus.com//foo'), 'http://sindresorhus.com/git://sindresorhus.com/foo');
+	t.is(normalizeUrl('http://sindresorhus.com//foo/git://sindresorhus.com//foo'), 'http://sindresorhus.com/foo/git://sindresorhus.com/foo');
+	t.is(normalizeUrl('http://sindresorhus.com/a://sindresorhus.com//foo'), 'http://sindresorhus.com/a:/sindresorhus.com/foo');
+	t.is(normalizeUrl('http://sindresorhus.com/alongprotocolwithin50charlimitxxxxxxxxxxxxxxxxxxxx://sindresorhus.com//foo'), 'http://sindresorhus.com/alongprotocolwithin50charlimitxxxxxxxxxxxxxxxxxxxx://sindresorhus.com/foo');
+	t.is(normalizeUrl('http://sindresorhus.com/alongprotocolexceeds50charlimitxxxxxxxxxxxxxxxxxxxxx://sindresorhus.com//foo'), 'http://sindresorhus.com/alongprotocolexceeds50charlimitxxxxxxxxxxxxxxxxxxxxx:/sindresorhus.com/foo');
+	t.is(normalizeUrl('http://sindresorhus.com/a2-.+://sindresorhus.com'), 'http://sindresorhus.com/a2-.+://sindresorhus.com');
+	t.is(normalizeUrl('http://sindresorhus.com/a2-.+_://sindresorhus.com'), 'http://sindresorhus.com/a2-.+_:/sindresorhus.com');
+	t.is(normalizeUrl('http://sindresorhus.com/2abc://sindresorhus.com'), 'http://sindresorhus.com/2abc:/sindresorhus.com');
 });
 
 test('data URL', t => {