UNPKG

@pnpm/git-resolver

Version:
176 lines 6.55 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const url_1 = __importStar(require("url")); const fetch_1 = __importDefault(require("@pnpm/fetch")); const graceful_git_1 = __importDefault(require("graceful-git")); const hosted_git_info_1 = __importDefault(require("hosted-git-info")); const gitProtocols = new Set([ 'git', 'git+http', 'git+https', 'git+rsync', 'git+ftp', 'git+file', 'git+ssh', 'ssh', ]); async function parsePref(pref) { const hosted = hosted_git_info_1.default.fromUrl(pref); if (hosted != null) { return fromHostedGit(hosted); } const colonsPos = pref.indexOf(':'); if (colonsPos === -1) return null; const protocol = pref.slice(0, colonsPos); if (protocol && gitProtocols.has(protocol.toLocaleLowerCase())) { const urlparse = new url_1.URL(escapeColon(pref)); if (!urlparse || !urlparse.protocol) return null; const match = urlparse.protocol === 'git+ssh:' && matchGitScp(pref); if (match) { return { ...match, normalizedPref: pref, }; } const committish = (urlparse.hash?.length > 1) ? decodeURIComponent(urlparse.hash.slice(1)) : null; return { fetchSpec: urlToFetchSpec(urlparse), normalizedPref: pref, ...setGitCommittish(committish), }; } return null; } exports.default = parsePref; function escapeColon(url) { if (!url.includes('@')) return url; const [front, ...backs] = url.split('@'); const escapedBacks = backs.map(e => e.replace(/:([^/\d]|\d+[^:/\d])/, ':/$1')); return [front, ...escapedBacks].join('@'); } function urlToFetchSpec(urlparse) { urlparse.hash = ''; const fetchSpec = url_1.default.format(urlparse); if (fetchSpec.startsWith('git+')) { return fetchSpec.slice(4); } return fetchSpec; } async function fromHostedGit(hosted) { let fetchSpec = null; // try git/https url before fallback to ssh url const gitUrl = hosted.https({ noCommittish: true }) ?? hosted.ssh({ noCommittish: true }); if (gitUrl && await accessRepository(gitUrl)) { fetchSpec = gitUrl; } if (!fetchSpec) { const httpsUrl = hosted.https({ noGitPlus: true, noCommittish: true }); if (httpsUrl) { if (hosted.auth && await accessRepository(httpsUrl)) { return { fetchSpec: httpsUrl, hosted: { ...hosted, _fill: hosted._fill, tarball: undefined, }, normalizedPref: `git+${httpsUrl}`, ...setGitCommittish(hosted.committish), }; } else { try { // when git ls-remote private repo, it asks for login credentials. // use HTTP HEAD request to test whether this is a private repo, to avoid login prompt. // this is very similar to yarn's behaviour. // npm instead tries git ls-remote directly which prompts user for login credentials. // HTTP HEAD on https://domain/user/repo, strip out ".git" const response = await (0, fetch_1.default)(httpsUrl.slice(0, -4), { method: 'HEAD', follow: 0, retry: { retries: 0 } }); if (response.ok) { fetchSpec = httpsUrl; } } catch (e) { // ignore } } } } if (!fetchSpec) { // use ssh url for likely private repo fetchSpec = hosted.sshurl({ noCommittish: true }); } return { fetchSpec: fetchSpec, hosted: { ...hosted, _fill: hosted._fill, tarball: hosted.tarball, }, normalizedPref: hosted.shortcut(), ...setGitCommittish(hosted.committish), }; } async function accessRepository(repository) { try { await (0, graceful_git_1.default)(['ls-remote', '--exit-code', repository, 'HEAD'], { retries: 0 }); return true; } catch (err) { // eslint-disable-line return false; } } function setGitCommittish(committish) { if (committish !== null && committish.length >= 7 && committish.slice(0, 7) === 'semver:') { return { gitCommittish: null, gitRange: committish.slice(7), }; } return { gitCommittish: committish }; } function matchGitScp(spec) { // git ssh specifiers are overloaded to also use scp-style git // specifiers, so we have to parse those out and treat them special. // They are NOT true URIs, so we can't hand them to `url.parse`. // // This regex looks for things that look like: // git+ssh://git@my.custom.git.com:username/project.git#deadbeef // // ...and various combinations. The username in the beginning is *required*. const matched = spec.match(/^git\+ssh:\/\/([^:]+:[^#]+(?:\.git)?)(?:#(.*))$/i); return (matched != null) && (matched[1].match(/:[0-9]+\/?.*$/i) == null) && { fetchSpec: matched[1], gitCommittish: matched[2], }; } //# sourceMappingURL=parsePref.js.map