123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778 |
- const url = require('url')
- const lastIndexOfBefore = (str, char, beforeChar) => {
- const startPosition = str.indexOf(beforeChar)
- return str.lastIndexOf(char, startPosition > -1 ? startPosition : Infinity)
- }
- const safeUrl = (u) => {
- try {
- return new url.URL(u)
- } catch {
- // this fn should never throw
- }
- }
- // accepts input like git:github.com:user/repo and inserts the // after the first :
- const correctProtocol = (arg, protocols) => {
- const firstColon = arg.indexOf(':')
- const proto = arg.slice(0, firstColon + 1)
- if (Object.prototype.hasOwnProperty.call(protocols, proto)) {
- return arg
- }
- const firstAt = arg.indexOf('@')
- if (firstAt > -1) {
- if (firstAt > firstColon) {
- return `git+ssh://${arg}`
- } else {
- return arg
- }
- }
- const doubleSlash = arg.indexOf('//')
- if (doubleSlash === firstColon + 1) {
- return arg
- }
- return `${arg.slice(0, firstColon + 1)}//${arg.slice(firstColon + 1)}`
- }
- // attempt to correct an scp style url so that it will parse with `new URL()`
- const correctUrl = (giturl) => {
- // ignore @ that come after the first hash since the denotes the start
- // of a committish which can contain @ characters
- const firstAt = lastIndexOfBefore(giturl, '@', '#')
- // ignore colons that come after the hash since that could include colons such as:
- // git@github.com:user/package-2#semver:^1.0.0
- const lastColonBeforeHash = lastIndexOfBefore(giturl, ':', '#')
- if (lastColonBeforeHash > firstAt) {
- // the last : comes after the first @ (or there is no @)
- // like it would in:
- // proto://hostname.com:user/repo
- // username@hostname.com:user/repo
- // :password@hostname.com:user/repo
- // username:password@hostname.com:user/repo
- // proto://username@hostname.com:user/repo
- // proto://:password@hostname.com:user/repo
- // proto://username:password@hostname.com:user/repo
- // then we replace the last : with a / to create a valid path
- giturl = giturl.slice(0, lastColonBeforeHash) + '/' + giturl.slice(lastColonBeforeHash + 1)
- }
- if (lastIndexOfBefore(giturl, ':', '#') === -1 && giturl.indexOf('//') === -1) {
- // we have no : at all
- // as it would be in:
- // username@hostname.com/user/repo
- // then we prepend a protocol
- giturl = `git+ssh://${giturl}`
- }
- return giturl
- }
- module.exports = (giturl, protocols) => {
- const withProtocol = protocols ? correctProtocol(giturl, protocols) : giturl
- return safeUrl(withProtocol) || safeUrl(correctUrl(withProtocol))
- }
|