"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());
    });
};
const mkdirp_1 = require('../fs/mkdirp');
const unsymlink_1 = require('../fs/unsymlink');
const link_dir_1 = require('link-dir');
const path = require('path');
const semver = require('semver');
/*
 * Links into `.store/node_modules`
 */
function linkPeers(store, installs) {
    return __awaiter(this, void 0, void 0, function* () {
        if (!installs)
            return;
        const peers = {};
        const roots = {};
        Object.keys(installs).forEach(name => {
            const pkgData = installs[name];
            const realname = pkgData.pkg.name;
            if (pkgData.keypath.length === 0) {
                roots[realname] = pkgData.pkg;
                return;
            }
            // NOTE: version is not always available
            // version is guaranteed to be there only for packages loaded from the npm registry
            if (!peers[realname] || peers[realname].pkg.version && pkgData.pkg.version &&
                semver.gt(pkgData.pkg.version, peers[realname].pkg.version, true)) {
                peers[realname] = pkgData;
            }
        });
        const modules = path.join(store, 'node_modules');
        yield mkdirp_1.default(modules);
        yield Promise.all(Object.keys(roots).map(name => {
            return unsymlink_1.default(path.join(modules, roots[name].name));
        }));
        yield Promise.all(Object.keys(peers).map(function (name) {
            return __awaiter(this, void 0, void 0, function* () {
                yield unsymlink_1.default(path.join(modules, peers[name].name));
                return link_dir_1.default(path.join(store, peers[name].id, '_'), path.join(modules, peers[name].name));
            });
        }));
    });
}
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = linkPeers;
function linkPeersWhenSymlinksPreserved(store, installs) {
    return __awaiter(this, void 0, void 0, function* () {
        if (!installs)
            return;
        const groupedPkgs = {};
        Object.keys(installs).forEach(id => {
            const pkgData = installs[id];
            if (!pkgData.pkg.version)
                return;
            const pkgName = pkgData.pkg.name;
            groupedPkgs[pkgName] = groupedPkgs[pkgName] || {};
            groupedPkgs[pkgName][pkgData.pkg.version] = pkgData;
        });
        return Promise.all(Object.keys(installs).map(id => {
            const pkgData = installs[id];
            const peerDependencies = pkgData.pkg.peerDependencies || {};
            return Promise.all(Object.keys(peerDependencies).map(peerName => {
                const version = semver.maxSatisfying(Object.keys(groupedPkgs[peerName] || {}), peerDependencies[peerName], true);
                if (!version) {
                    console.warn(`${pkgData.id} requires a peer of ${peerName}@${peerDependencies[peerName]} but none was installed.`);
                    return;
                }
                return link_dir_1.default(groupedPkgs[peerName][version].path, path.join(pkgData.path, 'node_modules', peerName));
            }));
        }));
    });
}
exports.linkPeersWhenSymlinksPreserved = linkPeersWhenSymlinksPreserved;
//# sourceMappingURL=linkPeers.js.map