@pnpm/git-resolver
Version:
Resolver for git-hosted packages
124 lines • 4.8 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createGitHostedPkgId = void 0;
exports.createGitResolver = createGitResolver;
const graceful_git_1 = __importDefault(require("graceful-git"));
const semver_1 = __importDefault(require("semver"));
const parseBareSpecifier_js_1 = require("./parseBareSpecifier.js");
const createGitHostedPkgId_js_1 = require("./createGitHostedPkgId.js");
Object.defineProperty(exports, "createGitHostedPkgId", { enumerable: true, get: function () { return createGitHostedPkgId_js_1.createGitHostedPkgId; } });
function createGitResolver(opts) {
return async function resolveGit(wantedDependency) {
const parsedSpec = await (0, parseBareSpecifier_js_1.parseBareSpecifier)(wantedDependency.bareSpecifier, opts);
if (parsedSpec == null)
return null;
const bareSpecifier = parsedSpec.gitCommittish == null || parsedSpec.gitCommittish === ''
? 'HEAD'
: parsedSpec.gitCommittish;
const commit = await resolveRef(parsedSpec.fetchSpec, bareSpecifier, parsedSpec.gitRange);
let resolution;
if ((parsedSpec.hosted != null) && !isSsh(parsedSpec.fetchSpec)) {
// don't use tarball for ssh url, they are likely private repo
const hosted = parsedSpec.hosted;
// use resolved committish
hosted.committish = commit;
const tarball = hosted.tarball?.();
if (tarball) {
resolution = { tarball };
}
}
if (resolution == null) {
resolution = {
commit,
repo: parsedSpec.fetchSpec,
type: 'git',
};
}
if (parsedSpec.path) {
resolution.path = parsedSpec.path;
}
let id;
if ('tarball' in resolution) {
id = resolution.tarball;
if (resolution.path) {
id = `${id}#path:${resolution.path}`;
}
}
else {
id = (0, createGitHostedPkgId_js_1.createGitHostedPkgId)(resolution);
}
return {
id,
normalizedBareSpecifier: parsedSpec.normalizedBareSpecifier,
resolution,
resolvedVia: 'git-repository',
};
};
}
function resolveVTags(vTags, range) {
return semver_1.default.maxSatisfying(vTags, range, true);
}
async function getRepoRefs(repo, ref) {
const gitArgs = [repo];
if (ref !== 'HEAD') {
gitArgs.unshift('--refs');
}
if (ref) {
gitArgs.push(ref);
}
// graceful-git by default retries 10 times, reduce to single retry
const result = await (0, graceful_git_1.default)(['ls-remote', ...gitArgs], { retries: 1 });
const refs = {};
for (const line of result.stdout.split('\n')) {
const [commit, refName] = line.split('\t');
refs[refName] = commit;
}
return refs;
}
async function resolveRef(repo, ref, range) {
if (ref.match(/^[0-9a-f]{7,40}$/) != null) {
return ref;
}
const refs = await getRepoRefs(repo, range ? null : ref);
return resolveRefFromRefs(refs, repo, ref, range);
}
function resolveRefFromRefs(refs, repo, ref, range) {
if (!range) {
const commitId = refs[ref] ||
refs[`refs/${ref}`] ||
refs[`refs/tags/${ref}^{}`] || // prefer annotated tags
refs[`refs/tags/${ref}`] ||
refs[`refs/heads/${ref}`];
if (!commitId) {
throw new Error(`Could not resolve ${ref} to a commit of ${repo}.`);
}
return commitId;
}
else {
const vTags = Object.keys(refs)
// using the same semantics of version tags as https://github.com/zkat/pacote
.filter((key) => /^refs\/tags\/v?\d+\.\d+\.\d+(?:[-+].+)?(?:\^\{\})?$/.test(key))
.map((key) => {
return key
.replace(/^refs\/tags\//, '')
.replace(/\^\{\}$/, ''); // accept annotated tags
})
.filter((key) => semver_1.default.valid(key, true));
const refVTag = resolveVTags(vTags, range);
const commitId = refVTag &&
(refs[`refs/tags/${refVTag}^{}`] || // prefer annotated tags
refs[`refs/tags/${refVTag}`]);
if (!commitId) {
throw new Error(`Could not resolve ${range} to a commit of ${repo}. Available versions are: ${vTags.join(', ')}`);
}
return commitId;
}
}
function isSsh(gitSpec) {
return gitSpec.slice(0, 10) === 'git+ssh://' ||
gitSpec.slice(0, 4) === 'git@';
}
//# sourceMappingURL=index.js.map