Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/npm/cli.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuy Adorno <ruyadorno@hotmail.com>2021-03-18 20:15:50 +0300
committerRuy Adorno <ruyadorno@hotmail.com>2021-03-18 20:15:50 +0300
commitaf7eaac5018ed821d72d43d08f1d7e49e7491453 (patch)
tree680b2c984b9f3fffe6ffdd8efd329e4761a59d83 /node_modules/hosted-git-info
parent33c853618db1540a2432807ebbef0ed52e90cbb5 (diff)
hosted-git-info@4.0.1
Diffstat (limited to 'node_modules/hosted-git-info')
-rw-r--r--node_modules/hosted-git-info/README.md4
-rw-r--r--node_modules/hosted-git-info/git-host-info.js211
-rw-r--r--node_modules/hosted-git-info/git-host.js222
-rw-r--r--node_modules/hosted-git-info/index.js299
-rw-r--r--node_modules/hosted-git-info/package.json26
5 files changed, 444 insertions, 318 deletions
diff --git a/node_modules/hosted-git-info/README.md b/node_modules/hosted-git-info/README.md
index 7b723f6b9..874040602 100644
--- a/node_modules/hosted-git-info/README.md
+++ b/node_modules/hosted-git-info/README.md
@@ -22,7 +22,7 @@ var info = hostedGitInfo.fromUrl("git@github.com:npm/hosted-git-info.git", opts)
If the URL can't be matched with a git host, `null` will be returned. We
can match git, ssh and https urls. Additionally, we can match ssh connect
strings (`git@github.com:npm/hosted-git-info`) and shortcuts (eg,
-`github:npm/hosted-git-info`). Github specifically, is detected in the case
+`github:npm/hosted-git-info`). GitHub specifically, is detected in the case
of a third, unprefixed, form: `npm/hosted-git-info`.
If it does match, the returned object has properties of:
@@ -129,5 +129,5 @@ SSH connect strings will be normalized into `git+ssh` URLs.
## Supported hosts
-Currently this supports Github, Bitbucket and Gitlab. Pull requests for
+Currently this supports GitHub, Bitbucket and GitLab. Pull requests for
additional hosts welcome.
diff --git a/node_modules/hosted-git-info/git-host-info.js b/node_modules/hosted-git-info/git-host-info.js
index da3348fa7..360d7b096 100644
--- a/node_modules/hosted-git-info/git-host-info.js
+++ b/node_modules/hosted-git-info/git-host-info.js
@@ -1,79 +1,154 @@
'use strict'
+const maybeJoin = (...args) => args.every(arg => arg) ? args.join('') : ''
+const maybeEncode = (arg) => arg ? encodeURIComponent(arg) : ''
-var gitHosts = module.exports = {
- github: {
- // First two are insecure and generally shouldn't be used any more, but
- // they are still supported.
- 'protocols': [ 'git', 'http', 'git+ssh', 'git+https', 'ssh', 'https' ],
- 'domain': 'github.com',
- 'treepath': 'tree',
- 'filetemplate': 'https://{auth@}raw.githubusercontent.com/{user}/{project}/{committish}/{path}',
- 'bugstemplate': 'https://{domain}/{user}/{project}/issues',
- 'gittemplate': 'git://{auth@}{domain}/{user}/{project}.git{#committish}',
- 'tarballtemplate': 'https://codeload.{domain}/{user}/{project}/tar.gz/{committish}'
- },
- bitbucket: {
- 'protocols': [ 'git+ssh', 'git+https', 'ssh', 'https' ],
- 'domain': 'bitbucket.org',
- 'treepath': 'src',
- 'tarballtemplate': 'https://{domain}/{user}/{project}/get/{committish}.tar.gz'
- },
- gitlab: {
- 'protocols': [ 'git+ssh', 'git+https', 'ssh', 'https' ],
- 'domain': 'gitlab.com',
- 'treepath': 'tree',
- 'bugstemplate': 'https://{domain}/{user}/{project}/issues',
- 'httpstemplate': 'git+https://{auth@}{domain}/{user}/{projectPath}.git{#committish}',
- 'tarballtemplate': 'https://{domain}/{user}/{project}/repository/archive.tar.gz?ref={committish}',
- 'pathmatch': /^\/([^/]+)\/((?!.*(\/-\/|\/repository(\/[^/]+)?\/archive\.tar\.gz)).*?)(?:\.git|\/)?$/
- },
- gist: {
- 'protocols': [ 'git', 'git+ssh', 'git+https', 'ssh', 'https' ],
- 'domain': 'gist.github.com',
- 'pathmatch': /^[/](?:([^/]+)[/])?([a-z0-9]{7,})(?:[.]git)?$/,
- 'filetemplate': 'https://gist.githubusercontent.com/{user}/{project}/raw{/committish}/{path}',
- 'bugstemplate': 'https://{domain}/{project}',
- 'gittemplate': 'git://{domain}/{project}.git{#committish}',
- 'sshtemplate': 'git@{domain}:/{project}.git{#committish}',
- 'sshurltemplate': 'git+ssh://git@{domain}/{project}.git{#committish}',
- 'browsetemplate': 'https://{domain}/{project}{/committish}',
- 'browsefiletemplate': 'https://{domain}/{project}{/committish}{#path}',
- 'docstemplate': 'https://{domain}/{project}{/committish}',
- 'httpstemplate': 'git+https://{domain}/{project}.git{#committish}',
- 'shortcuttemplate': '{type}:{project}{#committish}',
- 'pathtemplate': '{project}{#committish}',
- 'tarballtemplate': 'https://codeload.github.com/gist/{project}/tar.gz/{committish}',
- 'hashformat': function (fragment) {
- return 'file-' + formatHashFragment(fragment)
+const defaults = {
+ sshtemplate: ({ domain, user, project, committish }) => `git@${domain}:${user}/${project}.git${maybeJoin('#', committish)}`,
+ sshurltemplate: ({ domain, user, project, committish }) => `git+ssh://git@${domain}/${user}/${project}.git${maybeJoin('#', committish)}`,
+ browsetemplate: ({ domain, user, project, committish, treepath }) => `https://${domain}/${user}/${project}${maybeJoin('/', treepath, '/', maybeEncode(committish))}`,
+ browsefiletemplate: ({ domain, user, project, committish, treepath, path, fragment, hashformat }) => `https://${domain}/${user}/${project}/${treepath}/${maybeEncode(committish || 'master')}/${path}${maybeJoin('#', hashformat(fragment || ''))}`,
+ docstemplate: ({ domain, user, project, treepath, committish }) => `https://${domain}/${user}/${project}${maybeJoin('/', treepath, '/', maybeEncode(committish))}#readme`,
+ httpstemplate: ({ auth, domain, user, project, committish }) => `git+https://${maybeJoin(auth, '@')}${domain}/${user}/${project}.git${maybeJoin('#', committish)}`,
+ filetemplate: ({ domain, user, project, committish, path }) => `https://${domain}/${user}/${project}/raw/${maybeEncode(committish) || 'master'}/${path}`,
+ shortcuttemplate: ({ type, user, project, committish }) => `${type}:${user}/${project}${maybeJoin('#', committish)}`,
+ pathtemplate: ({ user, project, committish }) => `${user}/${project}${maybeJoin('#', committish)}`,
+ bugstemplate: ({ domain, user, project }) => `https://${domain}/${user}/${project}/issues`,
+ hashformat: formatHashFragment
+}
+
+const gitHosts = {}
+gitHosts.github = Object.assign({}, defaults, {
+ // First two are insecure and generally shouldn't be used any more, but
+ // they are still supported.
+ protocols: ['git:', 'http:', 'git+ssh:', 'git+https:', 'ssh:', 'https:'],
+ domain: 'github.com',
+ treepath: 'tree',
+ filetemplate: ({ auth, user, project, committish, path }) => `https://${maybeJoin(auth, '@')}raw.githubusercontent.com/${user}/${project}/${maybeEncode(committish) || 'master'}/${path}`,
+ gittemplate: ({ auth, domain, user, project, committish }) => `git://${maybeJoin(auth, '@')}${domain}/${user}/${project}.git${maybeJoin('#', committish)}`,
+ tarballtemplate: ({ domain, user, project, committish }) => `https://codeload.${domain}/${user}/${project}/tar.gz/${maybeEncode(committish) || 'master'}`,
+ extract: (url) => {
+ let [, user, project, type, committish] = url.pathname.split('/', 5)
+ if (type && type !== 'tree') {
+ return
+ }
+
+ if (!type) {
+ committish = url.hash.slice(1)
+ }
+
+ if (project && project.endsWith('.git')) {
+ project = project.slice(0, -4)
+ }
+
+ if (!user || !project) {
+ return
}
+
+ return { user, project, committish }
}
-}
+})
-var gitHostDefaults = {
- 'sshtemplate': 'git@{domain}:{user}/{project}.git{#committish}',
- 'sshurltemplate': 'git+ssh://git@{domain}/{user}/{project}.git{#committish}',
- 'browsetemplate': 'https://{domain}/{user}/{project}{/tree/committish}',
- 'browsefiletemplate': 'https://{domain}/{user}/{project}/{treepath}/{committish}/{path}{#fragment}',
- 'docstemplate': 'https://{domain}/{user}/{project}{/tree/committish}#readme',
- 'httpstemplate': 'git+https://{auth@}{domain}/{user}/{project}.git{#committish}',
- 'filetemplate': 'https://{domain}/{user}/{project}/raw/{committish}/{path}',
- 'shortcuttemplate': '{type}:{user}/{project}{#committish}',
- 'pathtemplate': '{user}/{project}{#committish}',
- 'pathmatch': /^[/]([^/]+)[/]([^/]+?)(?:[.]git|[/])?$/,
- 'hashformat': formatHashFragment
-}
+gitHosts.bitbucket = Object.assign({}, defaults, {
+ protocols: ['git+ssh:', 'git+https:', 'ssh:', 'https:'],
+ domain: 'bitbucket.org',
+ treepath: 'src',
+ tarballtemplate: ({ domain, user, project, committish }) => `https://${domain}/${user}/${project}/get/${maybeEncode(committish) || 'master'}.tar.gz`,
+ extract: (url) => {
+ let [, user, project, aux] = url.pathname.split('/', 4)
+ if (['get'].includes(aux)) {
+ return
+ }
+
+ if (project && project.endsWith('.git')) {
+ project = project.slice(0, -4)
+ }
+
+ if (!user || !project) {
+ return
+ }
+
+ return { user, project, committish: url.hash.slice(1) }
+ }
+})
+
+gitHosts.gitlab = Object.assign({}, defaults, {
+ protocols: ['git+ssh:', 'git+https:', 'ssh:', 'https:'],
+ domain: 'gitlab.com',
+ treepath: 'tree',
+ httpstemplate: ({ auth, domain, user, project, committish }) => `git+https://${maybeJoin(auth, '@')}${domain}/${user}/${project}.git${maybeJoin('#', committish)}`,
+ tarballtemplate: ({ domain, user, project, committish }) => `https://${domain}/${user}/${project}/repository/archive.tar.gz?ref=${maybeEncode(committish) || 'master'}`,
+ extract: (url) => {
+ const path = url.pathname.slice(1)
+ if (path.includes('/-/')) {
+ return
+ }
+
+ const segments = path.split('/')
+ let project = segments.pop()
+ if (project.endsWith('.git')) {
+ project = project.slice(0, -4)
+ }
+
+ const user = segments.join('/')
+ if (!user || !project) {
+ return
+ }
+
+ return { user, project, committish: url.hash.slice(1) }
+ }
+})
+
+gitHosts.gist = Object.assign({}, defaults, {
+ protocols: ['git:', 'git+ssh:', 'git+https:', 'ssh:', 'https:'],
+ domain: 'gist.github.com',
+ sshtemplate: ({ domain, project, committish }) => `git@${domain}:${project}.git${maybeJoin('#', committish)}`,
+ sshurltemplate: ({ domain, project, committish }) => `git+ssh://git@${domain}/${project}.git${maybeJoin('#', committish)}`,
+ browsetemplate: ({ domain, project, committish }) => `https://${domain}/${project}${maybeJoin('/', maybeEncode(committish))}`,
+ browsefiletemplate: ({ domain, project, committish, path, hashformat }) => `https://${domain}/${project}${maybeJoin('/', maybeEncode(committish))}${maybeJoin('#', hashformat(path))}`,
+ docstemplate: ({ domain, project, committish }) => `https://${domain}/${project}${maybeJoin('/', maybeEncode(committish))}`,
+ httpstemplate: ({ domain, project, committish }) => `git+https://${domain}/${project}.git${maybeJoin('#', committish)}`,
+ filetemplate: ({ user, project, committish, path }) => `https://gist.githubusercontent.com/${user}/${project}/raw${maybeJoin('/', maybeEncode(committish))}/${path}`,
+ shortcuttemplate: ({ type, project, committish }) => `${type}:${project}${maybeJoin('#', committish)}`,
+ pathtemplate: ({ project, committish }) => `${project}${maybeJoin('#', committish)}`,
+ bugstemplate: ({ domain, project }) => `https://${domain}/${project}`,
+ gittemplate: ({ domain, project, committish }) => `git://${domain}/${project}.git${maybeJoin('#', committish)}`,
+ tarballtemplate: ({ project, committish }) => `https://codeload.github.com/gist/${project}/tar.gz/${maybeEncode(committish) || 'master'}`,
+ extract: (url) => {
+ let [, user, project, aux] = url.pathname.split('/', 4)
+ if (aux === 'raw') {
+ return
+ }
+
+ if (!project) {
+ if (!user) {
+ return
+ }
+
+ project = user
+ user = null
+ }
+
+ if (project.endsWith('.git')) {
+ project = project.slice(0, -4)
+ }
-Object.keys(gitHosts).forEach(function (name) {
- Object.keys(gitHostDefaults).forEach(function (key) {
- if (gitHosts[name][key]) return
- gitHosts[name][key] = gitHostDefaults[key]
- })
- gitHosts[name].protocols_re = RegExp('^(' +
- gitHosts[name].protocols.map(function (protocol) {
- return protocol.replace(/([\\+*{}()[\]$^|])/g, '\\$1')
- }).join('|') + '):$')
+ return { user, project, committish: url.hash.slice(1) }
+ },
+ hashformat: function (fragment) {
+ return fragment && 'file-' + formatHashFragment(fragment)
+ }
})
+const names = Object.keys(gitHosts)
+gitHosts.byShortcut = {}
+gitHosts.byDomain = {}
+for (const name of names) {
+ gitHosts.byShortcut[`${name}:`] = name
+ gitHosts.byDomain[gitHosts[name].domain] = name
+}
+
function formatHashFragment (fragment) {
return fragment.toLowerCase().replace(/^\W+|\/|\W+$/g, '').replace(/\W+/g, '-')
}
+
+module.exports = gitHosts
diff --git a/node_modules/hosted-git-info/git-host.js b/node_modules/hosted-git-info/git-host.js
index f9b1ec745..8a975e92e 100644
--- a/node_modules/hosted-git-info/git-host.js
+++ b/node_modules/hosted-git-info/git-host.js
@@ -1,156 +1,110 @@
'use strict'
-var gitHosts = require('./git-host-info.js')
-/* eslint-disable node/no-deprecated-api */
-
-// copy-pasta util._extend from node's source, to avoid pulling
-// the whole util module into peoples' webpack bundles.
-/* istanbul ignore next */
-var extend = Object.assign || function _extend (target, source) {
- // Don't do anything if source isn't an object
- if (source === null || typeof source !== 'object') return target
-
- const keys = Object.keys(source)
- let i = keys.length
- while (i--) {
- target[keys[i]] = source[keys[i]]
- }
- return target
-}
+const gitHosts = require('./git-host-info.js')
+
+class GitHost {
+ constructor (type, user, auth, project, committish, defaultRepresentation, opts = {}) {
+ Object.assign(this, gitHosts[type])
+ this.type = type
+ this.user = user
+ this.auth = auth
+ this.project = project
+ this.committish = committish
+ this.default = defaultRepresentation
+ this.opts = opts
+ }
-module.exports = GitHost
-function GitHost (type, user, auth, project, committish, defaultRepresentation, opts) {
- var gitHostInfo = this
- gitHostInfo.type = type
- Object.keys(gitHosts[type]).forEach(function (key) {
- gitHostInfo[key] = gitHosts[type][key]
- })
- gitHostInfo.user = user
- gitHostInfo.auth = auth
- gitHostInfo.project = project
- gitHostInfo.committish = committish
- gitHostInfo.default = defaultRepresentation
- gitHostInfo.opts = opts || {}
-}
+ hash () {
+ return this.committish ? `#${this.committish}` : ''
+ }
-GitHost.prototype.hash = function () {
- return this.committish ? '#' + this.committish : ''
-}
+ ssh (opts) {
+ return this._fill(this.sshtemplate, opts)
+ }
+
+ _fill (template, opts) {
+ if (typeof template === 'function') {
+ const options = { ...this, ...this.opts, ...opts }
+
+ // the path should always be set so we don't end up with 'undefined' in urls
+ if (!options.path) {
+ options.path = ''
+ }
+
+ // template functions will insert the leading slash themselves
+ if (options.path.startsWith('/')) {
+ options.path = options.path.slice(1)
+ }
-GitHost.prototype._fill = function (template, opts) {
- if (!template) return
- var vars = extend({}, opts)
- vars.path = vars.path ? vars.path.replace(/^[/]+/g, '') : ''
- opts = extend(extend({}, this.opts), opts)
- var self = this
- Object.keys(this).forEach(function (key) {
- if (self[key] != null && vars[key] == null) vars[key] = self[key]
- })
- var rawAuth = vars.auth
- var rawcommittish = vars.committish
- var rawFragment = vars.fragment
- var rawPath = vars.path
- var rawProject = vars.project
- Object.keys(vars).forEach(function (key) {
- var value = vars[key]
- if ((key === 'path' || key === 'project') && typeof value === 'string') {
- vars[key] = value.split('/').map(function (pathComponent) {
- return encodeURIComponent(pathComponent)
- }).join('/')
- } else if (key !== 'domain') {
- vars[key] = encodeURIComponent(value)
+ if (options.noCommittish) {
+ options.committish = null
+ }
+
+ const result = template(options)
+ return options.noGitPlus && result.startsWith('git+') ? result.slice(4) : result
}
- })
- vars['auth@'] = rawAuth ? rawAuth + '@' : ''
- vars['#fragment'] = rawFragment ? '#' + this.hashformat(rawFragment) : ''
- vars.fragment = vars.fragment ? vars.fragment : ''
- vars['#path'] = rawPath ? '#' + this.hashformat(rawPath) : ''
- vars['/path'] = vars.path ? '/' + vars.path : ''
- vars.projectPath = rawProject.split('/').map(encodeURIComponent).join('/')
- if (opts.noCommittish) {
- vars['#committish'] = ''
- vars['/tree/committish'] = ''
- vars['/committish'] = ''
- vars.committish = ''
- } else {
- vars['#committish'] = rawcommittish ? '#' + rawcommittish : ''
- vars['/tree/committish'] = vars.committish
- ? '/' + vars.treepath + '/' + vars.committish
- : ''
- vars['/committish'] = vars.committish ? '/' + vars.committish : ''
- vars.committish = vars.committish || 'master'
- }
- var res = template
- Object.keys(vars).forEach(function (key) {
- res = res.replace(new RegExp('[{]' + key + '[}]', 'g'), vars[key])
- })
- if (opts.noGitPlus) {
- return res.replace(/^git[+]/, '')
- } else {
- return res
+
+ return null
}
-}
-GitHost.prototype.ssh = function (opts) {
- return this._fill(this.sshtemplate, opts)
-}
+ sshurl (opts) {
+ return this._fill(this.sshurltemplate, opts)
+ }
-GitHost.prototype.sshurl = function (opts) {
- return this._fill(this.sshurltemplate, opts)
-}
+ browse (path, fragment, opts) {
+ // not a string, treat path as opts
+ if (typeof path !== 'string') {
+ return this._fill(this.browsetemplate, path)
+ }
-GitHost.prototype.browse = function (P, F, opts) {
- if (typeof P === 'string') {
- if (typeof F !== 'string') {
- opts = F
- F = null
+ if (typeof fragment !== 'string') {
+ opts = fragment
+ fragment = null
}
- return this._fill(this.browsefiletemplate, extend({
- fragment: F,
- path: P
- }, opts))
- } else {
- return this._fill(this.browsetemplate, P)
+ return this._fill(this.browsefiletemplate, { ...opts, fragment, path })
}
-}
-GitHost.prototype.docs = function (opts) {
- return this._fill(this.docstemplate, opts)
-}
+ docs (opts) {
+ return this._fill(this.docstemplate, opts)
+ }
-GitHost.prototype.bugs = function (opts) {
- return this._fill(this.bugstemplate, opts)
-}
+ bugs (opts) {
+ return this._fill(this.bugstemplate, opts)
+ }
-GitHost.prototype.https = function (opts) {
- return this._fill(this.httpstemplate, opts)
-}
+ https (opts) {
+ return this._fill(this.httpstemplate, opts)
+ }
-GitHost.prototype.git = function (opts) {
- return this._fill(this.gittemplate, opts)
-}
+ git (opts) {
+ return this._fill(this.gittemplate, opts)
+ }
-GitHost.prototype.shortcut = function (opts) {
- return this._fill(this.shortcuttemplate, opts)
-}
+ shortcut (opts) {
+ return this._fill(this.shortcuttemplate, opts)
+ }
-GitHost.prototype.path = function (opts) {
- return this._fill(this.pathtemplate, opts)
-}
+ path (opts) {
+ return this._fill(this.pathtemplate, opts)
+ }
-GitHost.prototype.tarball = function (opts_) {
- var opts = extend({}, opts_, { noCommittish: false })
- return this._fill(this.tarballtemplate, opts)
-}
+ tarball (opts) {
+ return this._fill(this.tarballtemplate, { ...opts, noCommittish: false })
+ }
-GitHost.prototype.file = function (P, opts) {
- return this._fill(this.filetemplate, extend({ path: P }, opts))
-}
+ file (path, opts) {
+ return this._fill(this.filetemplate, { ...opts, path })
+ }
-GitHost.prototype.getDefaultRepresentation = function () {
- return this.default
-}
+ getDefaultRepresentation () {
+ return this.default
+ }
+
+ toString (opts) {
+ if (this.default && typeof this[this.default] === 'function') {
+ return this[this.default](opts)
+ }
-GitHost.prototype.toString = function (opts) {
- if (this.default && typeof this[this.default] === 'function') return this[this.default](opts)
- return this.sshurl(opts)
+ return this.sshurl(opts)
+ }
}
+module.exports = GitHost
diff --git a/node_modules/hosted-git-info/index.js b/node_modules/hosted-git-info/index.js
index 8b3eaba3d..f35c570c4 100644
--- a/node_modules/hosted-git-info/index.js
+++ b/node_modules/hosted-git-info/index.js
@@ -1,11 +1,11 @@
'use strict'
-var url = require('url')
-var gitHosts = require('./git-host-info.js')
-var GitHost = module.exports = require('./git-host.js')
-var LRU = require('lru-cache')
-var cache = new LRU({max: 1000})
+const url = require('url')
+const gitHosts = require('./git-host-info.js')
+const GitHost = module.exports = require('./git-host.js')
+const LRU = require('lru-cache')
+const cache = new LRU({ max: 1000 })
-var protocolToRepresentationMap = {
+const protocolToRepresentationMap = {
'git+ssh:': 'sshurl',
'git+https:': 'https',
'ssh:': 'sshurl',
@@ -16,7 +16,7 @@ function protocolToRepresentation (protocol) {
return protocolToRepresentationMap[protocol] || protocol.slice(0, -1)
}
-var authProtocols = {
+const authProtocols = {
'git:': true,
'https:': true,
'git+https:': true,
@@ -24,9 +24,14 @@ var authProtocols = {
'git+http:': true
}
+const knownProtocols = Object.keys(gitHosts.byShortcut).concat(['http:', 'https:', 'git:', 'git+ssh:', 'git+https:', 'ssh:'])
+
module.exports.fromUrl = function (giturl, opts) {
- if (typeof giturl !== 'string') return
- var key = giturl + JSON.stringify(opts || {})
+ if (typeof giturl !== 'string') {
+ return
+ }
+
+ const key = giturl + JSON.stringify(opts || {})
if (!cache.has(key)) {
cache.set(key, fromUrl(giturl, opts))
@@ -36,111 +41,197 @@ module.exports.fromUrl = function (giturl, opts) {
}
function fromUrl (giturl, opts) {
- if (giturl == null || giturl === '') return
- var url = fixupUnqualifiedGist(
- isGitHubShorthand(giturl) ? 'github:' + giturl : giturl
- )
- var parsed = parseGitUrl(url)
- var shortcutMatch = url.match(/^([^:]+):(?:[^@]+@)?(?:([^/]*)\/)?([^#]+)/)
- var matches = Object.keys(gitHosts).map(function (gitHostName) {
- try {
- var gitHostInfo = gitHosts[gitHostName]
- var auth = null
- if (parsed.auth && authProtocols[parsed.protocol]) {
- auth = parsed.auth
+ if (!giturl) {
+ return
+ }
+
+ const url = isGitHubShorthand(giturl) ? 'github:' + giturl : correctProtocol(giturl)
+ const parsed = parseGitUrl(url)
+ if (!parsed) {
+ return parsed
+ }
+
+ const gitHostShortcut = gitHosts.byShortcut[parsed.protocol]
+ const gitHostDomain = gitHosts.byDomain[parsed.hostname.startsWith('www.') ? parsed.hostname.slice(4) : parsed.hostname]
+ const gitHostName = gitHostShortcut || gitHostDomain
+ if (!gitHostName) {
+ return
+ }
+
+ const gitHostInfo = gitHosts[gitHostShortcut || gitHostDomain]
+ let auth = null
+ if (authProtocols[parsed.protocol] && (parsed.username || parsed.password)) {
+ auth = `${parsed.username}${parsed.password ? ':' + parsed.password : ''}`
+ }
+
+ let committish = null
+ let user = null
+ let project = null
+ let defaultRepresentation = null
+
+ try {
+ if (gitHostShortcut) {
+ let pathname = parsed.pathname.startsWith('/') ? parsed.pathname.slice(1) : parsed.pathname
+ const firstAt = pathname.indexOf('@')
+ // we ignore auth for shortcuts, so just trim it out
+ if (firstAt > -1) {
+ pathname = pathname.slice(firstAt + 1)
}
- var committish = parsed.hash ? decodeURIComponent(parsed.hash.substr(1)) : null
- var user = null
- var project = null
- var defaultRepresentation = null
- if (shortcutMatch && shortcutMatch[1] === gitHostName) {
- user = shortcutMatch[2] && decodeURIComponent(shortcutMatch[2])
- project = decodeURIComponent(shortcutMatch[3].replace(/\.git$/, ''))
- defaultRepresentation = 'shortcut'
- } else {
- if (parsed.host && parsed.host !== gitHostInfo.domain && parsed.host.replace(/^www[.]/, '') !== gitHostInfo.domain) return
- if (!gitHostInfo.protocols_re.test(parsed.protocol)) return
- if (!parsed.path) return
- var pathmatch = gitHostInfo.pathmatch
- var matched = parsed.path.match(pathmatch)
- if (!matched) return
- /* istanbul ignore else */
- if (matched[1] !== null && matched[1] !== undefined) {
- user = decodeURIComponent(matched[1].replace(/^:/, ''))
+
+ const lastSlash = pathname.lastIndexOf('/')
+ if (lastSlash > -1) {
+ user = decodeURIComponent(pathname.slice(0, lastSlash))
+ // we want nulls only, never empty strings
+ if (!user) {
+ user = null
}
- project = decodeURIComponent(matched[2])
- defaultRepresentation = protocolToRepresentation(parsed.protocol)
+ project = decodeURIComponent(pathname.slice(lastSlash + 1))
+ } else {
+ project = decodeURIComponent(pathname)
+ }
+
+ if (project.endsWith('.git')) {
+ project = project.slice(0, -4)
+ }
+
+ if (parsed.hash) {
+ committish = decodeURIComponent(parsed.hash.slice(1))
+ }
+
+ defaultRepresentation = 'shortcut'
+ } else {
+ if (!gitHostInfo.protocols.includes(parsed.protocol)) {
+ return
}
- return new GitHost(gitHostName, user, auth, project, committish, defaultRepresentation, opts)
- } catch (ex) {
- /* istanbul ignore else */
- if (ex instanceof URIError) {
- } else throw ex
+
+ const segments = gitHostInfo.extract(parsed)
+ if (!segments) {
+ return
+ }
+
+ user = segments.user && decodeURIComponent(segments.user)
+ project = decodeURIComponent(segments.project)
+ committish = decodeURIComponent(segments.committish)
+ defaultRepresentation = protocolToRepresentation(parsed.protocol)
}
- }).filter(function (gitHostInfo) { return gitHostInfo })
- if (matches.length !== 1) return
- return matches[0]
-}
+ } catch (err) {
+ /* istanbul ignore else */
+ if (err instanceof URIError) {
+ return
+ } else {
+ throw err
+ }
+ }
-function isGitHubShorthand (arg) {
- // Note: This does not fully test the git ref format.
- // See https://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html
- //
- // The only way to do this properly would be to shell out to
- // git-check-ref-format, and as this is a fast sync function,
- // we don't want to do that. Just let git fail if it turns
- // out that the commit-ish is invalid.
- // GH usernames cannot start with . or -
- return /^[^:@%/\s.-][^:@%/\s]*[/][^:@\s/%]+(?:#.*)?$/.test(arg)
+ return new GitHost(gitHostName, user, auth, project, committish, defaultRepresentation, opts)
}
-function fixupUnqualifiedGist (giturl) {
- // necessary for round-tripping gists
- var parsed = url.parse(giturl)
- if (parsed.protocol === 'gist:' && parsed.host && !parsed.path) {
- return parsed.protocol + '/' + parsed.host
- } else {
- return giturl
+// accepts input like git:github.com:user/repo and inserts the // after the first :
+const correctProtocol = (arg) => {
+ const firstColon = arg.indexOf(':')
+ const proto = arg.slice(0, firstColon + 1)
+ if (knownProtocols.includes(proto)) {
+ return arg
}
-}
-function parseGitUrl (giturl) {
- var matched = giturl.match(/^([^@]+)@([^:/]+):[/]?((?:[^/]+[/])?[^/]+?)(?:[.]git)?(#.*)?$/)
- if (!matched) {
- var legacy = url.parse(giturl)
- if (legacy.auth) {
- // git urls can be in the form of scp-style/ssh-connect strings, like
- // git+ssh://user@host.com:some/path, which the legacy url parser
- // supports, but WhatWG url.URL class does not. However, the legacy
- // parser de-urlencodes the username and password, so something like
- // https://user%3An%40me:p%40ss%3Aword@x.com/ becomes
- // https://user:n@me:p@ss:word@x.com/ which is all kinds of wrong.
- // Pull off just the auth and host, so we dont' get the confusing
- // scp-style URL, then pass that to the WhatWG parser to get the
- // auth properly escaped.
- const authmatch = giturl.match(/[^@]+@[^:/]+/)
- /* istanbul ignore else - this should be impossible */
- if (authmatch) {
- var whatwg = new url.URL(authmatch[0])
- legacy.auth = whatwg.username || ''
- if (whatwg.password) legacy.auth += ':' + whatwg.password
- }
+ const firstAt = arg.indexOf('@')
+ if (firstAt > -1) {
+ if (firstAt > firstColon) {
+ return `git+ssh://${arg}`
+ } else {
+ return arg
}
- return legacy
}
- return {
- protocol: 'git+ssh:',
- slashes: true,
- auth: matched[1],
- host: matched[2],
- port: null,
- hostname: matched[2],
- hash: matched[4],
- search: null,
- query: null,
- pathname: '/' + matched[3],
- path: '/' + matched[3],
- href: 'git+ssh://' + matched[1] + '@' + matched[2] +
- '/' + matched[3] + (matched[4] || '')
+
+ const doubleSlash = arg.indexOf('//')
+ if (doubleSlash === firstColon + 1) {
+ return arg
+ }
+
+ return arg.slice(0, firstColon + 1) + '//' + arg.slice(firstColon + 1)
+}
+
+// look for github shorthand inputs, such as npm/cli
+const isGitHubShorthand = (arg) => {
+ // it cannot contain whitespace before the first #
+ // it cannot start with a / because that's probably an absolute file path
+ // but it must include a slash since repos are username/repository
+ // it cannot start with a . because that's probably a relative file path
+ // it cannot start with an @ because that's a scoped package if it passes the other tests
+ // it cannot contain a : before a # because that tells us that there's a protocol
+ // a second / may not exist before a #
+ const firstHash = arg.indexOf('#')
+ const firstSlash = arg.indexOf('/')
+ const secondSlash = arg.indexOf('/', firstSlash + 1)
+ const firstColon = arg.indexOf(':')
+ const firstSpace = /\s/.exec(arg)
+ const firstAt = arg.indexOf('@')
+
+ const spaceOnlyAfterHash = !firstSpace || (firstHash > -1 && firstSpace.index > firstHash)
+ const atOnlyAfterHash = firstAt === -1 || (firstHash > -1 && firstAt > firstHash)
+ const colonOnlyAfterHash = firstColon === -1 || (firstHash > -1 && firstColon > firstHash)
+ const secondSlashOnlyAfterHash = secondSlash === -1 || (firstHash > -1 && secondSlash > firstHash)
+ const hasSlash = firstSlash > 0
+ // if a # is found, what we really want to know is that the character immediately before # is not a /
+ const doesNotEndWithSlash = firstHash > -1 ? arg[firstHash - 1] !== '/' : !arg.endsWith('/')
+ const doesNotStartWithDot = !arg.startsWith('.')
+
+ return spaceOnlyAfterHash && hasSlash && doesNotEndWithSlash && doesNotStartWithDot && atOnlyAfterHash && colonOnlyAfterHash && secondSlashOnlyAfterHash
+}
+
+// attempt to correct an scp style url so that it will parse with `new URL()`
+const correctUrl = (giturl) => {
+ const firstAt = giturl.indexOf('@')
+ const lastHash = giturl.lastIndexOf('#')
+ let firstColon = giturl.indexOf(':')
+ let lastColon = giturl.lastIndexOf(':', lastHash > -1 ? lastHash : Infinity)
+
+ let corrected
+ if (lastColon > 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
+ corrected = giturl.slice(0, lastColon) + '/' + giturl.slice(lastColon + 1)
+ // // and we find our new : positions
+ firstColon = corrected.indexOf(':')
+ lastColon = corrected.lastIndexOf(':')
+ }
+
+ if (firstColon === -1 && giturl.indexOf('//') === -1) {
+ // we have no : at all
+ // as it would be in:
+ // username@hostname.com/user/repo
+ // then we prepend a protocol
+ corrected = `git+ssh://${corrected}`
+ }
+
+ return corrected
+}
+
+// try to parse the url as its given to us, if that throws
+// then we try to clean the url and parse that result instead
+// THIS FUNCTION SHOULD NEVER THROW
+const parseGitUrl = (giturl) => {
+ let result
+ try {
+ result = new url.URL(giturl)
+ } catch (err) {}
+
+ if (result) {
+ return result
}
+
+ const correctedUrl = correctUrl(giturl)
+ try {
+ result = new url.URL(correctedUrl)
+ } catch (err) {}
+
+ return result
}
diff --git a/node_modules/hosted-git-info/package.json b/node_modules/hosted-git-info/package.json
index 32712269f..930e3b693 100644
--- a/node_modules/hosted-git-info/package.json
+++ b/node_modules/hosted-git-info/package.json
@@ -1,7 +1,7 @@
{
"name": "hosted-git-info",
- "version": "3.0.8",
- "description": "Provides metadata and conversions from repository urls for Github, Bitbucket and Gitlab",
+ "version": "4.0.1",
+ "description": "Provides metadata and conversions from repository urls for GitHub, Bitbucket and GitLab",
"main": "index.js",
"repository": {
"type": "git",
@@ -20,20 +20,21 @@
},
"homepage": "https://github.com/npm/hosted-git-info",
"scripts": {
- "prerelease": "npm t",
- "postrelease": "npm publish && git push --follow-tags",
"posttest": "standard",
- "release": "standard-version -s",
- "test:coverage": "tap --coverage-report=html -J --100 --no-esm test/*.js",
- "test": "tap -J --100 --no-esm test/*.js"
+ "postversion": "npm publish",
+ "prepublishOnly": "git push origin --follow-tags",
+ "preversion": "npm test",
+ "snap": "tap",
+ "test": "tap",
+ "test:coverage": "tap --coverage-report=html"
},
"dependencies": {
"lru-cache": "^6.0.0"
},
"devDependencies": {
- "standard": "^11.0.1",
- "standard-version": "^4.4.0",
- "tap": "^12.7.0"
+ "standard": "^16.0.3",
+ "standard-version": "^9.1.0",
+ "tap": "^14.11.0"
},
"files": [
"index.js",
@@ -42,5 +43,10 @@
],
"engines": {
"node": ">=10"
+ },
+ "tap": {
+ "color": 1,
+ "coverage": true,
+ "esm": false
}
}