1/* eslint-disable max-len */ 2 3'use strict' 4 5const maybeJoin = (...args) => args.every(arg => arg) ? args.join('') : '' 6const maybeEncode = (arg) => arg ? encodeURIComponent(arg) : '' 7const formatHashFragment = (f) => f.toLowerCase().replace(/^\W+|\/|\W+$/g, '').replace(/\W+/g, '-') 8 9const defaults = { 10 sshtemplate: ({ domain, user, project, committish }) => 11 `git@${domain}:${user}/${project}.git${maybeJoin('#', committish)}`, 12 sshurltemplate: ({ domain, user, project, committish }) => 13 `git+ssh://git@${domain}/${user}/${project}.git${maybeJoin('#', committish)}`, 14 edittemplate: ({ domain, user, project, committish, editpath, path }) => 15 `https://${domain}/${user}/${project}${maybeJoin('/', editpath, '/', maybeEncode(committish || 'HEAD'), '/', path)}`, 16 browsetemplate: ({ domain, user, project, committish, treepath }) => 17 `https://${domain}/${user}/${project}${maybeJoin('/', treepath, '/', maybeEncode(committish))}`, 18 browsetreetemplate: ({ domain, user, project, committish, treepath, path, fragment, hashformat }) => 19 `https://${domain}/${user}/${project}/${treepath}/${maybeEncode(committish || 'HEAD')}/${path}${maybeJoin('#', hashformat(fragment || ''))}`, 20 browseblobtemplate: ({ domain, user, project, committish, blobpath, path, fragment, hashformat }) => 21 `https://${domain}/${user}/${project}/${blobpath}/${maybeEncode(committish || 'HEAD')}/${path}${maybeJoin('#', hashformat(fragment || ''))}`, 22 docstemplate: ({ domain, user, project, treepath, committish }) => 23 `https://${domain}/${user}/${project}${maybeJoin('/', treepath, '/', maybeEncode(committish))}#readme`, 24 httpstemplate: ({ auth, domain, user, project, committish }) => 25 `git+https://${maybeJoin(auth, '@')}${domain}/${user}/${project}.git${maybeJoin('#', committish)}`, 26 filetemplate: ({ domain, user, project, committish, path }) => 27 `https://${domain}/${user}/${project}/raw/${maybeEncode(committish || 'HEAD')}/${path}`, 28 shortcuttemplate: ({ type, user, project, committish }) => 29 `${type}:${user}/${project}${maybeJoin('#', committish)}`, 30 pathtemplate: ({ user, project, committish }) => 31 `${user}/${project}${maybeJoin('#', committish)}`, 32 bugstemplate: ({ domain, user, project }) => 33 `https://${domain}/${user}/${project}/issues`, 34 hashformat: formatHashFragment, 35} 36 37const hosts = {} 38hosts.github = { 39 // First two are insecure and generally shouldn't be used any more, but 40 // they are still supported. 41 protocols: ['git:', 'http:', 'git+ssh:', 'git+https:', 'ssh:', 'https:'], 42 domain: 'github.com', 43 treepath: 'tree', 44 blobpath: 'blob', 45 editpath: 'edit', 46 filetemplate: ({ auth, user, project, committish, path }) => 47 `https://${maybeJoin(auth, '@')}raw.githubusercontent.com/${user}/${project}/${maybeEncode(committish || 'HEAD')}/${path}`, 48 gittemplate: ({ auth, domain, user, project, committish }) => 49 `git://${maybeJoin(auth, '@')}${domain}/${user}/${project}.git${maybeJoin('#', committish)}`, 50 tarballtemplate: ({ domain, user, project, committish }) => 51 `https://codeload.${domain}/${user}/${project}/tar.gz/${maybeEncode(committish || 'HEAD')}`, 52 extract: (url) => { 53 let [, user, project, type, committish] = url.pathname.split('/', 5) 54 if (type && type !== 'tree') { 55 return 56 } 57 58 if (!type) { 59 committish = url.hash.slice(1) 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 } 71 }, 72} 73 74hosts.bitbucket = { 75 protocols: ['git+ssh:', 'git+https:', 'ssh:', 'https:'], 76 domain: 'bitbucket.org', 77 treepath: 'src', 78 blobpath: 'src', 79 editpath: '?mode=edit', 80 edittemplate: ({ domain, user, project, committish, treepath, path, editpath }) => 81 `https://${domain}/${user}/${project}${maybeJoin('/', treepath, '/', maybeEncode(committish || 'HEAD'), '/', path, editpath)}`, 82 tarballtemplate: ({ domain, user, project, committish }) => 83 `https://${domain}/${user}/${project}/get/${maybeEncode(committish || 'HEAD')}.tar.gz`, 84 extract: (url) => { 85 let [, user, project, aux] = url.pathname.split('/', 4) 86 if (['get'].includes(aux)) { 87 return 88 } 89 90 if (project && project.endsWith('.git')) { 91 project = project.slice(0, -4) 92 } 93 94 if (!user || !project) { 95 return 96 } 97 98 return { user, project, committish: url.hash.slice(1) } 99 }, 100} 101 102hosts.gitlab = { 103 protocols: ['git+ssh:', 'git+https:', 'ssh:', 'https:'], 104 domain: 'gitlab.com', 105 treepath: 'tree', 106 blobpath: 'tree', 107 editpath: '-/edit', 108 httpstemplate: ({ auth, domain, user, project, committish }) => 109 `git+https://${maybeJoin(auth, '@')}${domain}/${user}/${project}.git${maybeJoin('#', committish)}`, 110 tarballtemplate: ({ domain, user, project, committish }) => 111 `https://${domain}/${user}/${project}/repository/archive.tar.gz?ref=${maybeEncode(committish || 'HEAD')}`, 112 extract: (url) => { 113 const path = url.pathname.slice(1) 114 if (path.includes('/-/') || path.includes('/archive.tar.gz')) { 115 return 116 } 117 118 const segments = path.split('/') 119 let project = segments.pop() 120 if (project.endsWith('.git')) { 121 project = project.slice(0, -4) 122 } 123 124 const user = segments.join('/') 125 if (!user || !project) { 126 return 127 } 128 129 return { user, project, committish: url.hash.slice(1) } 130 }, 131} 132 133hosts.gist = { 134 protocols: ['git:', 'git+ssh:', 'git+https:', 'ssh:', 'https:'], 135 domain: 'gist.github.com', 136 editpath: 'edit', 137 sshtemplate: ({ domain, project, committish }) => 138 `git@${domain}:${project}.git${maybeJoin('#', committish)}`, 139 sshurltemplate: ({ domain, project, committish }) => 140 `git+ssh://git@${domain}/${project}.git${maybeJoin('#', committish)}`, 141 edittemplate: ({ domain, user, project, committish, editpath }) => 142 `https://${domain}/${user}/${project}${maybeJoin('/', maybeEncode(committish))}/${editpath}`, 143 browsetemplate: ({ domain, project, committish }) => 144 `https://${domain}/${project}${maybeJoin('/', maybeEncode(committish))}`, 145 browsetreetemplate: ({ domain, project, committish, path, hashformat }) => 146 `https://${domain}/${project}${maybeJoin('/', maybeEncode(committish))}${maybeJoin('#', hashformat(path))}`, 147 browseblobtemplate: ({ domain, project, committish, path, hashformat }) => 148 `https://${domain}/${project}${maybeJoin('/', maybeEncode(committish))}${maybeJoin('#', hashformat(path))}`, 149 docstemplate: ({ domain, project, committish }) => 150 `https://${domain}/${project}${maybeJoin('/', maybeEncode(committish))}`, 151 httpstemplate: ({ domain, project, committish }) => 152 `git+https://${domain}/${project}.git${maybeJoin('#', committish)}`, 153 filetemplate: ({ user, project, committish, path }) => 154 `https://gist.githubusercontent.com/${user}/${project}/raw${maybeJoin('/', maybeEncode(committish))}/${path}`, 155 shortcuttemplate: ({ type, project, committish }) => 156 `${type}:${project}${maybeJoin('#', committish)}`, 157 pathtemplate: ({ project, committish }) => 158 `${project}${maybeJoin('#', committish)}`, 159 bugstemplate: ({ domain, project }) => 160 `https://${domain}/${project}`, 161 gittemplate: ({ domain, project, committish }) => 162 `git://${domain}/${project}.git${maybeJoin('#', committish)}`, 163 tarballtemplate: ({ project, committish }) => 164 `https://codeload.github.com/gist/${project}/tar.gz/${maybeEncode(committish || 'HEAD')}`, 165 extract: (url) => { 166 let [, user, project, aux] = url.pathname.split('/', 4) 167 if (aux === 'raw') { 168 return 169 } 170 171 if (!project) { 172 if (!user) { 173 return 174 } 175 176 project = user 177 user = null 178 } 179 180 if (project.endsWith('.git')) { 181 project = project.slice(0, -4) 182 } 183 184 return { user, project, committish: url.hash.slice(1) } 185 }, 186 hashformat: function (fragment) { 187 return fragment && 'file-' + formatHashFragment(fragment) 188 }, 189} 190 191hosts.sourcehut = { 192 protocols: ['git+ssh:', 'https:'], 193 domain: 'git.sr.ht', 194 treepath: 'tree', 195 blobpath: 'tree', 196 filetemplate: ({ domain, user, project, committish, path }) => 197 `https://${domain}/${user}/${project}/blob/${maybeEncode(committish) || 'HEAD'}/${path}`, 198 httpstemplate: ({ domain, user, project, committish }) => 199 `https://${domain}/${user}/${project}.git${maybeJoin('#', committish)}`, 200 tarballtemplate: ({ domain, user, project, committish }) => 201 `https://${domain}/${user}/${project}/archive/${maybeEncode(committish) || 'HEAD'}.tar.gz`, 202 bugstemplate: ({ user, project }) => null, 203 extract: (url) => { 204 let [, user, project, aux] = url.pathname.split('/', 4) 205 206 // tarball url 207 if (['archive'].includes(aux)) { 208 return 209 } 210 211 if (project && project.endsWith('.git')) { 212 project = project.slice(0, -4) 213 } 214 215 if (!user || !project) { 216 return 217 } 218 219 return { user, project, committish: url.hash.slice(1) } 220 }, 221} 222 223for (const [name, host] of Object.entries(hosts)) { 224 hosts[name] = Object.assign({}, defaults, host) 225} 226 227module.exports = hosts 228