Skip to content

Commit 3cd4a98

Browse files
committed
fix: ignore colons after hash when correcting scp urls
Fixes #148
1 parent 88d450f commit 3cd4a98

File tree

2 files changed

+72
-78
lines changed

2 files changed

+72
-78
lines changed

lib/index.js

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ function protocolToRepresentation (protocol) {
1616
return protocolToRepresentationMap[protocol] || protocol.slice(0, -1)
1717
}
1818

19+
function lastIndexOfBefore (str, char, beforeChar) {
20+
const startPosition = str.lastIndexOf(beforeChar)
21+
return str.lastIndexOf(char, startPosition > -1 ? startPosition : Infinity)
22+
}
23+
1924
const authProtocols = {
2025
'git:': true,
2126
'https:': true,
@@ -189,12 +194,11 @@ const isGitHubShorthand = (arg) => {
189194
// attempt to correct an scp style url so that it will parse with `new URL()`
190195
const correctUrl = (giturl) => {
191196
const firstAt = giturl.indexOf('@')
192-
const lastHash = giturl.lastIndexOf('#')
193-
let firstColon = giturl.indexOf(':')
194-
let lastColon = giturl.lastIndexOf(':', lastHash > -1 ? lastHash : Infinity)
197+
// ignore colons that come after the hash since that could include colons such as:
198+
// git@github.com:user/package-2#semver:^1.0.0
199+
const lastColonBeforeHash = lastIndexOfBefore(giturl, ':', '#')
195200

196-
let corrected
197-
if (lastColon > firstAt) {
201+
if (lastColonBeforeHash > firstAt) {
198202
// the last : comes after the first @ (or there is no @)
199203
// like it would in:
200204
// proto://hostname.com:user/repo
@@ -205,44 +209,33 @@ const correctUrl = (giturl) => {
205209
// proto://:password@hostname.com:user/repo
206210
// proto://username:password@hostname.com:user/repo
207211
// then we replace the last : with a / to create a valid path
208-
corrected = giturl.slice(0, lastColon) + '/' + giturl.slice(lastColon + 1)
209-
// // and we find our new : positions
210-
firstColon = corrected.indexOf(':')
211-
lastColon = corrected.lastIndexOf(':')
212+
giturl = giturl.slice(0, lastColonBeforeHash) + '/' + giturl.slice(lastColonBeforeHash + 1)
212213
}
213214

214-
if (firstColon === -1 && giturl.indexOf('//') === -1) {
215+
if (lastIndexOfBefore(giturl, ':', '#') === -1 && giturl.indexOf('//') === -1) {
215216
// we have no : at all
216217
// as it would be in:
217218
// username@hostname.com/user/repo
218219
// then we prepend a protocol
219-
corrected = `git+ssh://${corrected}`
220+
giturl = `git+ssh://${giturl}`
220221
}
221222

222-
return corrected
223+
return giturl
223224
}
224225

225226
// try to parse the url as its given to us, if that throws
226227
// then we try to clean the url and parse that result instead
227228
// THIS FUNCTION SHOULD NEVER THROW
228229
const parseGitUrl = (giturl) => {
229-
let result
230230
try {
231-
result = new url.URL(giturl)
231+
return new url.URL(giturl)
232232
} catch {
233233
// this fn should never throw
234234
}
235235

236-
if (result) {
237-
return result
238-
}
239-
240-
const correctedUrl = correctUrl(giturl)
241236
try {
242-
result = new url.URL(correctedUrl)
237+
return new url.URL(correctUrl(giturl))
243238
} catch {
244239
// this fn should never throw
245240
}
246-
247-
return result
248241
}

0 commit comments

Comments
 (0)