Skip to content

Commit c218b9e

Browse files
authored
rewrite the entire module (#80)
* feat! rewrite the world all internals have been rewritten to maintain a similar contract but to remove excessive use of regular expressions, unnecessary loops, the custom string templating engine, and various other bits of complexity BREAKING CHANGE extending with custom providers has changed
1 parent deab507 commit c218b9e

10 files changed

+5434
-4112
lines changed

git-host-info.js

+143-68
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,154 @@
11
'use strict'
2+
const maybeJoin = (...args) => args.every(arg => arg) ? args.join('') : ''
3+
const maybeEncode = (arg) => arg ? encodeURIComponent(arg) : ''
24

3-
var gitHosts = module.exports = {
4-
github: {
5-
// First two are insecure and generally shouldn't be used any more, but
6-
// they are still supported.
7-
'protocols': [ 'git', 'http', 'git+ssh', 'git+https', 'ssh', 'https' ],
8-
'domain': 'github.com',
9-
'treepath': 'tree',
10-
'filetemplate': 'https://{auth@}raw.githubusercontent.com/{user}/{project}/{committish}/{path}',
11-
'bugstemplate': 'https://{domain}/{user}/{project}/issues',
12-
'gittemplate': 'git://{auth@}{domain}/{user}/{project}.git{#committish}',
13-
'tarballtemplate': 'https://codeload.{domain}/{user}/{project}/tar.gz/{committish}'
14-
},
15-
bitbucket: {
16-
'protocols': [ 'git+ssh', 'git+https', 'ssh', 'https' ],
17-
'domain': 'bitbucket.org',
18-
'treepath': 'src',
19-
'tarballtemplate': 'https://{domain}/{user}/{project}/get/{committish}.tar.gz'
20-
},
21-
gitlab: {
22-
'protocols': [ 'git+ssh', 'git+https', 'ssh', 'https' ],
23-
'domain': 'gitlab.com',
24-
'treepath': 'tree',
25-
'bugstemplate': 'https://{domain}/{user}/{project}/issues',
26-
'httpstemplate': 'git+https://{auth@}{domain}/{user}/{projectPath}.git{#committish}',
27-
'tarballtemplate': 'https://{domain}/{user}/{project}/repository/archive.tar.gz?ref={committish}',
28-
'pathmatch': /^\/([^/]+)\/((?!.*(\/-\/|\/repository(\/[^/]+)?\/archive\.tar\.gz)).*?)(?:\.git|\/)?$/
29-
},
30-
gist: {
31-
'protocols': [ 'git', 'git+ssh', 'git+https', 'ssh', 'https' ],
32-
'domain': 'gist.github.com',
33-
'pathmatch': /^[/](?:([^/]+)[/])?([a-z0-9]{7,})(?:[.]git)?$/,
34-
'filetemplate': 'https://gist.githubusercontent.com/{user}/{project}/raw{/committish}/{path}',
35-
'bugstemplate': 'https://{domain}/{project}',
36-
'gittemplate': 'git://{domain}/{project}.git{#committish}',
37-
'sshtemplate': 'git@{domain}:/{project}.git{#committish}',
38-
'sshurltemplate': 'git+ssh://git@{domain}/{project}.git{#committish}',
39-
'browsetemplate': 'https://{domain}/{project}{/committish}',
40-
'browsefiletemplate': 'https://{domain}/{project}{/committish}{#path}',
41-
'docstemplate': 'https://{domain}/{project}{/committish}',
42-
'httpstemplate': 'git+https://{domain}/{project}.git{#committish}',
43-
'shortcuttemplate': '{type}:{project}{#committish}',
44-
'pathtemplate': '{project}{#committish}',
45-
'tarballtemplate': 'https://codeload.github.com/gist/{project}/tar.gz/{committish}',
46-
'hashformat': function (fragment) {
47-
return 'file-' + formatHashFragment(fragment)
5+
const defaults = {
6+
sshtemplate: ({ domain, user, project, committish }) => `git@${domain}:${user}/${project}.git${maybeJoin('#', committish)}`,
7+
sshurltemplate: ({ domain, user, project, committish }) => `git+ssh://git@${domain}/${user}/${project}.git${maybeJoin('#', committish)}`,
8+
browsetemplate: ({ domain, user, project, committish, treepath }) => `https://${domain}/${user}/${project}${maybeJoin('/', treepath, '/', maybeEncode(committish))}`,
9+
browsefiletemplate: ({ domain, user, project, committish, treepath, path, fragment, hashformat }) => `https://${domain}/${user}/${project}/${treepath}/${maybeEncode(committish || 'master')}/${path}${maybeJoin('#', hashformat(fragment || ''))}`,
10+
docstemplate: ({ domain, user, project, treepath, committish }) => `https://${domain}/${user}/${project}${maybeJoin('/', treepath, '/', maybeEncode(committish))}#readme`,
11+
httpstemplate: ({ auth, domain, user, project, committish }) => `git+https://${maybeJoin(auth, '@')}${domain}/${user}/${project}.git${maybeJoin('#', committish)}`,
12+
filetemplate: ({ domain, user, project, committish, path }) => `https://${domain}/${user}/${project}/raw/${maybeEncode(committish) || 'master'}/${path}`,
13+
shortcuttemplate: ({ type, user, project, committish }) => `${type}:${user}/${project}${maybeJoin('#', committish)}`,
14+
pathtemplate: ({ user, project, committish }) => `${user}/${project}${maybeJoin('#', committish)}`,
15+
bugstemplate: ({ domain, user, project }) => `https://${domain}/${user}/${project}/issues`,
16+
hashformat: formatHashFragment
17+
}
18+
19+
const gitHosts = {}
20+
gitHosts.github = Object.assign({}, defaults, {
21+
// First two are insecure and generally shouldn't be used any more, but
22+
// they are still supported.
23+
protocols: ['git:', 'http:', 'git+ssh:', 'git+https:', 'ssh:', 'https:'],
24+
domain: 'github.com',
25+
treepath: 'tree',
26+
filetemplate: ({ auth, user, project, committish, path }) => `https://${maybeJoin(auth, '@')}raw.githubusercontent.com/${user}/${project}/${maybeEncode(committish) || 'master'}/${path}`,
27+
gittemplate: ({ auth, domain, user, project, committish }) => `git://${maybeJoin(auth, '@')}${domain}/${user}/${project}.git${maybeJoin('#', committish)}`,
28+
tarballtemplate: ({ domain, user, project, committish }) => `https://codeload.${domain}/${user}/${project}/tar.gz/${maybeEncode(committish) || 'master'}`,
29+
extract: (url) => {
30+
let [, user, project, type, committish] = url.pathname.split('/', 5)
31+
if (type && type !== 'tree') {
32+
return
33+
}
34+
35+
if (!type) {
36+
committish = url.hash.slice(1)
37+
}
38+
39+
if (project && project.endsWith('.git')) {
40+
project = project.slice(0, -4)
41+
}
42+
43+
if (!user || !project) {
44+
return
4845
}
46+
47+
return { user, project, committish }
4948
}
50-
}
49+
})
5150

52-
var gitHostDefaults = {
53-
'sshtemplate': 'git@{domain}:{user}/{project}.git{#committish}',
54-
'sshurltemplate': 'git+ssh://git@{domain}/{user}/{project}.git{#committish}',
55-
'browsetemplate': 'https://{domain}/{user}/{project}{/tree/committish}',
56-
'browsefiletemplate': 'https://{domain}/{user}/{project}/{treepath}/{committish}/{path}{#fragment}',
57-
'docstemplate': 'https://{domain}/{user}/{project}{/tree/committish}#readme',
58-
'httpstemplate': 'git+https://{auth@}{domain}/{user}/{project}.git{#committish}',
59-
'filetemplate': 'https://{domain}/{user}/{project}/raw/{committish}/{path}',
60-
'shortcuttemplate': '{type}:{user}/{project}{#committish}',
61-
'pathtemplate': '{user}/{project}{#committish}',
62-
'pathmatch': /^[/]([^/]+)[/]([^/]+?)(?:[.]git|[/])?$/,
63-
'hashformat': formatHashFragment
64-
}
51+
gitHosts.bitbucket = Object.assign({}, defaults, {
52+
protocols: ['git+ssh:', 'git+https:', 'ssh:', 'https:'],
53+
domain: 'bitbucket.org',
54+
treepath: 'src',
55+
tarballtemplate: ({ domain, user, project, committish }) => `https://${domain}/${user}/${project}/get/${maybeEncode(committish) || 'master'}.tar.gz`,
56+
extract: (url) => {
57+
let [, user, project, aux] = url.pathname.split('/', 4)
58+
if (['get'].includes(aux)) {
59+
return
60+
}
61+
62+
if (project && project.endsWith('.git')) {
63+
project = project.slice(0, -4)
64+
}
65+
66+
if (!user || !project) {
67+
return
68+
}
69+
70+
return { user, project, committish: url.hash.slice(1) }
71+
}
72+
})
73+
74+
gitHosts.gitlab = Object.assign({}, defaults, {
75+
protocols: ['git+ssh:', 'git+https:', 'ssh:', 'https:'],
76+
domain: 'gitlab.com',
77+
treepath: 'tree',
78+
httpstemplate: ({ auth, domain, user, project, committish }) => `git+https://${maybeJoin(auth, '@')}${domain}/${user}/${project}.git${maybeJoin('#', committish)}`,
79+
tarballtemplate: ({ domain, user, project, committish }) => `https://${domain}/${user}/${project}/repository/archive.tar.gz?ref=${maybeEncode(committish) || 'master'}`,
80+
extract: (url) => {
81+
const path = url.pathname.slice(1)
82+
if (path.includes('/-/')) {
83+
return
84+
}
85+
86+
const segments = path.split('/')
87+
let project = segments.pop()
88+
if (project.endsWith('.git')) {
89+
project = project.slice(0, -4)
90+
}
91+
92+
const user = segments.join('/')
93+
if (!user || !project) {
94+
return
95+
}
96+
97+
return { user, project, committish: url.hash.slice(1) }
98+
}
99+
})
100+
101+
gitHosts.gist = Object.assign({}, defaults, {
102+
protocols: ['git:', 'git+ssh:', 'git+https:', 'ssh:', 'https:'],
103+
domain: 'gist.github.com',
104+
sshtemplate: ({ domain, project, committish }) => `git@${domain}:${project}.git${maybeJoin('#', committish)}`,
105+
sshurltemplate: ({ domain, project, committish }) => `git+ssh://git@${domain}/${project}.git${maybeJoin('#', committish)}`,
106+
browsetemplate: ({ domain, project, committish }) => `https://${domain}/${project}${maybeJoin('/', maybeEncode(committish))}`,
107+
browsefiletemplate: ({ domain, project, committish, path, hashformat }) => `https://${domain}/${project}${maybeJoin('/', maybeEncode(committish))}${maybeJoin('#', hashformat(path))}`,
108+
docstemplate: ({ domain, project, committish }) => `https://${domain}/${project}${maybeJoin('/', maybeEncode(committish))}`,
109+
httpstemplate: ({ domain, project, committish }) => `git+https://${domain}/${project}.git${maybeJoin('#', committish)}`,
110+
filetemplate: ({ user, project, committish, path }) => `https://gist.githubusercontent.com/${user}/${project}/raw${maybeJoin('/', maybeEncode(committish))}/${path}`,
111+
shortcuttemplate: ({ type, project, committish }) => `${type}:${project}${maybeJoin('#', committish)}`,
112+
pathtemplate: ({ project, committish }) => `${project}${maybeJoin('#', committish)}`,
113+
bugstemplate: ({ domain, project }) => `https://${domain}/${project}`,
114+
gittemplate: ({ domain, project, committish }) => `git://${domain}/${project}.git${maybeJoin('#', committish)}`,
115+
tarballtemplate: ({ project, committish }) => `https://codeload.github.com/gist/${project}/tar.gz/${maybeEncode(committish) || 'master'}`,
116+
extract: (url) => {
117+
let [, user, project, aux] = url.pathname.split('/', 4)
118+
if (aux === 'raw') {
119+
return
120+
}
121+
122+
if (!project) {
123+
if (!user) {
124+
return
125+
}
126+
127+
project = user
128+
user = null
129+
}
130+
131+
if (project.endsWith('.git')) {
132+
project = project.slice(0, -4)
133+
}
65134

66-
Object.keys(gitHosts).forEach(function (name) {
67-
Object.keys(gitHostDefaults).forEach(function (key) {
68-
if (gitHosts[name][key]) return
69-
gitHosts[name][key] = gitHostDefaults[key]
70-
})
71-
gitHosts[name].protocols_re = RegExp('^(' +
72-
gitHosts[name].protocols.map(function (protocol) {
73-
return protocol.replace(/([\\+*{}()[\]$^|])/g, '\\$1')
74-
}).join('|') + '):$')
135+
return { user, project, committish: url.hash.slice(1) }
136+
},
137+
hashformat: function (fragment) {
138+
return fragment && 'file-' + formatHashFragment(fragment)
139+
}
75140
})
76141

142+
const names = Object.keys(gitHosts)
143+
gitHosts.byShortcut = {}
144+
gitHosts.byDomain = {}
145+
for (const name of names) {
146+
gitHosts.byShortcut[`${name}:`] = name
147+
gitHosts.byDomain[gitHosts[name].domain] = name
148+
}
149+
77150
function formatHashFragment (fragment) {
78151
return fragment.toLowerCase().replace(/^\W+|\/|\W+$/g, '').replace(/\W+/g, '-')
79152
}
153+
154+
module.exports = gitHosts

0 commit comments

Comments
 (0)