UNPKG

3.47 kBJavaScriptView Raw
1'use strict'
2var url = require('url')
3var gitHosts = require('./git-host-info.js')
4var GitHost = module.exports = require('./git-host.js')
5
6var protocolToRepresentationMap = {
7 'git+ssh': 'sshurl',
8 'git+https': 'https',
9 'ssh': 'sshurl',
10 'git': 'git'
11}
12
13function protocolToRepresentation (protocol) {
14 if (protocol.substr(-1) === ':') protocol = protocol.slice(0, -1)
15 return protocolToRepresentationMap[protocol] || protocol
16}
17
18var authProtocols = {
19 'git:': true,
20 'https:': true,
21 'git+https:': true,
22 'http:': true,
23 'git+http:': true
24}
25
26module.exports.fromUrl = function (giturl) {
27 if (giturl == null || giturl === '') return
28 var url = fixupUnqualifiedGist(
29 isGitHubShorthand(giturl) ? 'github:' + giturl : giturl
30 )
31 var parsed = parseGitUrl(url)
32 var matches = Object.keys(gitHosts).map(function (gitHostName) {
33 var gitHostInfo = gitHosts[gitHostName]
34 var auth = null
35 if (parsed.auth && authProtocols[parsed.protocol]) {
36 auth = decodeURIComponent(parsed.auth)
37 }
38 var committish = parsed.hash ? decodeURIComponent(parsed.hash.substr(1)) : null
39 var user = null
40 var project = null
41 var defaultRepresentation = null
42 if (parsed.protocol === gitHostName + ':') {
43 user = decodeURIComponent(parsed.host)
44 project = parsed.path && decodeURIComponent(parsed.path.replace(/^[/](.*?)(?:[.]git)?$/, '$1'))
45 defaultRepresentation = 'shortcut'
46 } else {
47 if (parsed.host !== gitHostInfo.domain) return
48 if (!gitHostInfo.protocols_re.test(parsed.protocol)) return
49 var pathmatch = gitHostInfo.pathmatch
50 var matched = parsed.path.match(pathmatch)
51 if (!matched) return
52 if (matched[1] != null) user = decodeURIComponent(matched[1])
53 if (matched[2] != null) project = decodeURIComponent(matched[2])
54 defaultRepresentation = protocolToRepresentation(parsed.protocol)
55 }
56 return new GitHost(gitHostName, user, auth, project, committish, defaultRepresentation)
57 }).filter(function (gitHostInfo) { return gitHostInfo })
58 if (matches.length !== 1) return
59 return matches[0]
60}
61
62function isGitHubShorthand (arg) {
63 // Note: This does not fully test the git ref format.
64 // See https://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html
65 //
66 // The only way to do this properly would be to shell out to
67 // git-check-ref-format, and as this is a fast sync function,
68 // we don't want to do that. Just let git fail if it turns
69 // out that the commit-ish is invalid.
70 // GH usernames cannot start with . or -
71 return /^[^:@%/\s.-][^:@%/\s]*[/][^:@\s/%]+(?:#.*)?$/.test(arg)
72}
73
74function fixupUnqualifiedGist (giturl) {
75 // necessary for round-tripping gists
76 var parsed = url.parse(giturl)
77 if (parsed.protocol === 'gist:' && parsed.host && !parsed.path) {
78 return parsed.protocol + '/' + parsed.host
79 } else {
80 return giturl
81 }
82}
83
84function parseGitUrl (giturl) {
85 if (typeof giturl !== 'string') giturl = '' + giturl
86 var matched = giturl.match(/^([^@]+)@([^:]+):[/]?((?:[^/]+[/])?[^/]+?)(?:[.]git)?(#.*)?$/)
87 if (!matched) return url.parse(giturl)
88 return {
89 protocol: 'git+ssh:',
90 slashes: true,
91 auth: matched[1],
92 host: matched[2],
93 port: null,
94 hostname: matched[2],
95 hash: matched[4],
96 search: null,
97 query: null,
98 pathname: '/' + matched[3],
99 path: '/' + matched[3],
100 href: 'git+ssh://' + matched[1] + '@' + matched[2] +
101 '/' + matched[3] + (matched[4] || '')
102 }
103}