"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 core_loggers_1 = require("@pnpm/core-loggers");
const logger_1 = require("@pnpm/logger");
const modules_yaml_1 = require("@pnpm/modules-yaml");
const types_1 = require("@pnpm/types");
const utils_1 = require("@pnpm/utils");
const mkdirp = require("mkdirp-promise");
const pnpm_shrinkwrap_1 = require("pnpm-shrinkwrap");
const removeAllExceptOuterLinks = require("remove-all-except-outer-links");
const errorTypes_1 = require("../errorTypes");
const checkCompatibility_1 = require("./checkCompatibility");
const readShrinkwrapFiles_1 = require("./readShrinkwrapFiles");
function getContext(opts, installType) {
    return __awaiter(this, void 0, void 0, function* () {
        const storePath = opts.store;
        const virtualStoreDir = yield utils_1.realNodeModulesDir(opts.shrinkwrapDirectory);
        const modules = yield modules_yaml_1.read(virtualStoreDir);
        if (modules) {
            yield validateNodeModules(modules, opts.importers, {
                force: opts.force && installType === 'general',
                include: opts.include,
                independentLeaves: opts.independentLeaves,
                shrinkwrapDirectory: opts.shrinkwrapDirectory,
                store: opts.store,
            });
        }
        yield mkdirp(storePath);
        const ctx = Object.assign({ importers: yield Promise.all(opts.importers.map((importer) => __awaiter(this, void 0, void 0, function* () {
                let pkg = (yield utils_1.safeReadPackageFromDir(importer.prefix)) || {};
                pkg = opts.hooks && opts.hooks.readPackage ? opts.hooks.readPackage(pkg) : pkg;
                core_loggers_1.packageJsonLogger.debug({
                    initial: pkg,
                    prefix: importer.prefix,
                });
                return {
                    bin: importer.bin,
                    hoistedAliases: modules && modules.importers[importer.id] && modules.importers[importer.id].hoistedAliases || {},
                    id: importer.id,
                    modulesDir: yield utils_1.realNodeModulesDir(importer.prefix),
                    pkg,
                    prefix: importer.prefix,
                    shamefullyFlatten: Boolean(importer.shamefullyFlatten || modules && modules.importers[importer.id] && modules.importers[importer.id].shamefullyFlatten),
                };
            }))), include: opts.include || modules && modules.included || { dependencies: true, devDependencies: true, optionalDependencies: true }, modulesFile: modules, pendingBuilds: modules && modules.pendingBuilds || [], shrinkwrapDirectory: opts.shrinkwrapDirectory, skipped: new Set(modules && modules.skipped || []), storePath,
            virtualStoreDir }, yield readShrinkwrapFiles_1.default({
            force: opts.force,
            importerIds: opts.importers.map((importer) => importer.id),
            registry: opts.registry,
            shrinkwrap: opts.shrinkwrap,
            shrinkwrapDirectory: opts.shrinkwrapDirectory,
        }));
        return ctx;
    });
}
exports.default = getContext;
function validateNodeModules(modules, importers, opts) {
    return __awaiter(this, void 0, void 0, function* () {
        if (Boolean(modules.independentLeaves) !== opts.independentLeaves) {
            if (opts.force) {
                yield Promise.all(importers.map((importer) => __awaiter(this, void 0, void 0, function* () {
                    logger_1.default.info({
                        message: `Recreating ${importer.modulesDir}`,
                        prefix: importer.prefix,
                    });
                    yield removeAllExceptOuterLinks(importer.modulesDir);
                })));
                return;
            }
            if (modules.independentLeaves) {
                throw new errorTypes_1.PnpmError('ERR_PNPM_INDEPENDENT_LEAVES_WANTED', 'This "node_modules" folder was created using the --independent-leaves option.'
                    + ' You must add that option, or else run "pnpm install --force" to recreate the "node_modules" folder.');
            }
            throw new errorTypes_1.PnpmError('ERR_PNPM_INDEPENDENT_LEAVES_NOT_WANTED', 'This "node_modules" folder was created without the --independent-leaves option.'
                + ' You must remove that option, or else "pnpm install --force" to recreate the "node_modules" folder.');
        }
        yield Promise.all(importers.map((importer) => __awaiter(this, void 0, void 0, function* () {
            try {
                if (modules.importers && modules.importers[importer.id] && Boolean(modules.importers[importer.id].shamefullyFlatten) !== importer.shamefullyFlatten) {
                    if (modules.importers[importer.id].shamefullyFlatten) {
                        throw new errorTypes_1.PnpmError('ERR_PNPM_SHAMEFULLY_FLATTEN_WANTED', 'This "node_modules" folder was created using the --shamefully-flatten option.'
                            + ' You must add this option, or else add the --force option to recreate the "node_modules" folder.');
                    }
                    throw new errorTypes_1.PnpmError('ERR_PNPM_SHAMEFULLY_FLATTEN_NOT_WANTED', 'This "node_modules" folder was created without the --shamefully-flatten option.'
                        + ' You must remove that option, or else add the --force option to recreate the "node_modules" folder.');
                }
                checkCompatibility_1.default(modules, { storePath: opts.store, modulesPath: importer.modulesDir });
                if (opts.shrinkwrapDirectory !== importer.prefix && opts.include && modules.included) {
                    for (const depsField of types_1.DEPENDENCIES_FIELDS) {
                        if (opts.include[depsField] !== modules.included[depsField]) {
                            throw new errorTypes_1.PnpmError('ERR_PNPM_INCLUDED_DEPS_CONFLICT', `node_modules (at "${opts.shrinkwrapDirectory}") was installed with ${stringifyIncludedDeps(modules.included)}. ` +
                                `Current install wants ${stringifyIncludedDeps(opts.include)}.`);
                        }
                    }
                }
            }
            catch (err) {
                if (!opts.force)
                    throw err;
                logger_1.default.info({
                    message: `Recreating ${importer.modulesDir}`,
                    prefix: importer.prefix,
                });
                yield removeAllExceptOuterLinks(importer.modulesDir);
            }
        })));
    });
}
function stringifyIncludedDeps(included) {
    return types_1.DEPENDENCIES_FIELDS.filter((depsField) => included[depsField]).join(', ');
}
function getContextForSingleImporter(opts) {
    return __awaiter(this, void 0, void 0, function* () {
        const storePath = opts.store;
        const shrinkwrapDirectory = opts.shrinkwrapDirectory || opts.prefix;
        const virtualStoreDir = yield utils_1.realNodeModulesDir(shrinkwrapDirectory);
        const modules = yield modules_yaml_1.read(virtualStoreDir);
        const modulesDir = yield utils_1.realNodeModulesDir(opts.prefix);
        const importerId = pnpm_shrinkwrap_1.getImporterId(shrinkwrapDirectory, opts.prefix);
        if (modules) {
            const importers = [
                {
                    id: importerId,
                    modulesDir,
                    prefix: opts.prefix,
                    shamefullyFlatten: opts.shamefullyFlatten,
                },
            ];
            yield validateNodeModules(modules, importers, {
                force: opts.force,
                include: opts.include,
                independentLeaves: opts.independentLeaves,
                shrinkwrapDirectory: opts.shrinkwrapDirectory,
                store: opts.store,
            });
        }
        const files = yield Promise.all([
            utils_1.safeReadPackageFromDir(opts.prefix),
            mkdirp(storePath),
        ]);
        const pkg = files[0] || {};
        const ctx = Object.assign({ hoistedAliases: modules && modules.importers[importerId] && modules.importers[importerId].hoistedAliases || {}, importerId, include: opts.include || modules && modules.included || { dependencies: true, devDependencies: true, optionalDependencies: true }, modulesDir, modulesFile: modules, pendingBuilds: modules && modules.pendingBuilds || [], pkg: opts.hooks && opts.hooks.readPackage ? opts.hooks.readPackage(pkg) : pkg, prefix: opts.prefix, shrinkwrapDirectory, skipped: new Set(modules && modules.skipped || []), storePath,
            virtualStoreDir }, yield readShrinkwrapFiles_1.default({
            force: opts.force,
            importerIds: [importerId],
            registry: opts.registry,
            shrinkwrap: opts.shrinkwrap,
            shrinkwrapDirectory,
        }));
        core_loggers_1.packageJsonLogger.debug({
            initial: pkg,
            prefix: opts.prefix,
        });
        return ctx;
    });
}
exports.getContextForSingleImporter = getContextForSingleImporter;
//# sourceMappingURL=index.js.map