"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 logInstallStatus_1 = require("../../logging/logInstallStatus");
const loadPackageMeta_1 = require("./loadPackageMeta");
const createNpmPkgId_1 = require("./createNpmPkgId");
const getHost_1 = require("./getHost");
/**
 * 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)
                logInstallStatus_1.default({ status: 'resolving', pkg: opts.loggedPkg });
            const meta = yield loadPackageMeta_1.default(spec, {
                localRegistry: opts.localRegistry,
                registry: opts.registry,
                got: opts.got,
                metaCache: opts.metaCache,
                offline: opts.offline,
            });
            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 registryHost = getHost_1.default(correctPkg.dist.tarball);
            const id = createNpmPkgId_1.default(registryHost, correctPkg.name, correctPkg.version);
            const resolution = {
                shasum: correctPkg.dist.shasum,
                tarball: correctPkg.dist.tarball,
            };
            return { id, resolution, package: correctPkg };
        }
        catch (err) {
            if (err['statusCode'] === 404) {
                throw new Error("Module '" + spec.raw + "' not found");
            }
            throw err;
        }
    });
}
exports.default = resolveNpm;
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'];
    if (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