"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 path = require("path");
const mkdirp_1 = require("../fs/mkdirp");
const hardlinkDir_1 = require("../fs/hardlinkDir");
function flattenDependencies(id, store, pkgs, graph) {
    const newPkgs = getNewPkgs(pkgs, [id]);
    const todo = new Set(newPkgs.map(newPkg => newPkg.id).concat([id]));
    const tree = {};
    flattenPkgs(id, graph, 1, [], tree);
    return createFlatTree(id, store, id, graph, todo, tree, 1);
}
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = flattenDependencies;
function getNewPkgs(pkgs, keypath) {
    return pkgs.filter(pkg => !pkg.fromCache).concat(pkgs
        .filter(pkg => keypath.indexOf(pkg.id) === -1)
        .reduce((newPkgs, pkg) => newPkgs.concat(getNewPkgs(pkg.dependencies, keypath.concat([pkg.id]))), []));
}
function createFlatTree(id, store, root, graph, todo, tree, depth) {
    return __awaiter(this, void 0, void 0, function* () {
        if (!todo.has(id))
            return;
        todo.delete(id);
        const modules = path.join(root, 'node_modules');
        yield mkdirp_1.default(modules);
        yield Promise.all(Object.keys(tree[id])
            .map(function (depName) {
            return __awaiter(this, void 0, void 0, function* () {
                if (!tree || !tree[id] || !tree[id][depName])
                    throw new Error('Error during creating flat tree');
                const target = path.join(store, tree[id][depName].id);
                if (tree[id][depName].depth > depth) {
                    yield hardlinkDir_1.default(target, path.join(modules, depName));
                }
                return createFlatTree(tree[id][depName].id, store, target, graph, todo, tree, depth + 1);
            });
        }));
    });
}
function flattenPkgs(id, graph, depth, keypath, tree) {
    if (tree[id])
        return tree[id];
    if (keypath.indexOf(id) !== -1)
        return {};
    tree[id] = Object.keys(graph[id].dependencies || {})
        .reduce((prev, depName) => {
        const depId = graph[id].dependencies[depName];
        const subdeps = flattenPkgs(depId, graph, depth + 1, keypath.concat([id]), tree);
        prev[depName] = {
            id: depId,
            depth,
        };
        return Object.assign({}, subdeps, prev);
    }, {});
    return tree[id];
}
//# sourceMappingURL=flattenDependencies.js.map