"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const semver = require("semver");
const ssri = require("ssri");
const loggers_1 = require("../../loggers");
const createNpmPkgId_1 = require("./createNpmPkgId");
const loadPackageMeta_1 = require("./loadPackageMeta");
/**
 * Resolves a package in the NPM registry. Done as part of `install()`.
 *
 * @example
 *     var npa = require('npm-package-arg')
 *     resolve(npa('rimraf@2'))
 *       .then((res) => {
 *         res.id == 'rimraf@2.5.1'
 *         res.dist == {
 *           shasum: '0a1b2c...'
 *           tarball: 'http://...'
 *         }
 *       })
 */
function resolveNpm(spec, opts) {
    return __awaiter(this, void 0, void 0, function* () {
        // { raw: 'rimraf@2', scope: null, name: 'rimraf', rawSpec: '2' || '' }
        try {
            if (opts.loggedPkg) {
                loggers_1.progressLogger.debug({ status: 'resolving', pkg: opts.loggedPkg });
            }
            const meta = yield loadPackageMeta_1.default(spec, {
                downloadPriority: opts.downloadPriority,
                got: opts.got,
                metaCache: opts.metaCache,
                offline: opts.offline,
                registry: opts.registry,
                storePath: opts.storePath,
            });
            const correctPkg = pickVersion(meta, spec);
            if (!correctPkg) {
                const versions = Object.keys(meta.versions);
                const message = versions.length
                    ? 'Versions in registry:\n' + versions.join(', ') + '\n'
                    : 'No valid version found.';
                const err = new Error('No compatible version found: ' +
                    spec.raw + '\n' + message);
                throw err;
            }
            const id = createNpmPkgId_1.default(correctPkg.dist.tarball, correctPkg.name, correctPkg.version);
            const resolution = {
                integrity: getIntegrity(correctPkg.dist),
                registry: opts.registry,
                tarball: correctPkg.dist.tarball,
            };
            return {
                id,
                latest: meta['dist-tags'].latest,
                package: correctPkg,
                resolution,
            };
        }
        catch (err) {
            if (err.statusCode === 404) {
                throw new Error("Module '" + spec.raw + "' not found");
            }
            throw err;
        }
    });
}
exports.default = resolveNpm;
function getIntegrity(dist) {
    if (dist.integrity) {
        return dist.integrity;
    }
    return ssri.fromHex(dist.shasum, 'sha1').toString();
}
function pickVersion(meta, dep) {
    if (dep.type === 'tag') {
        return pickVersionByTag(meta, dep.fetchSpec);
    }
    return pickVersionByVersionRange(meta, dep.fetchSpec);
}
function pickVersionByTag(meta, tag) {
    const tagVersion = meta['dist-tags'][tag];
    if (meta.versions[tagVersion]) {
        return meta.versions[tagVersion];
    }
    return null;
}
function pickVersionByVersionRange(meta, versionRange) {
    const latest = meta['dist-tags'].latest;
    // Not using semver.satisfies in case of * because it does not select beta versions.
    // E.g.: 1.0.0-beta.1. See issue: https://github.com/pnpm/pnpm/issues/865
    if (versionRange === '*' || semver.satisfies(latest, versionRange, true)) {
        return meta.versions[latest];
    }
    const versions = Object.keys(meta.versions);
    const maxVersion = semver.maxSatisfying(versions, versionRange, true);
    if (maxVersion) {
        return meta.versions[maxVersion];
    }
    return null;
}
//# sourceMappingURL=index.js.map