"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 logger_1 = require("@pnpm/logger");
const npa = require("@zkochan/npm-package-arg");
const dp = require("dependency-path");
const pSeries = require("p-series");
const path = require("path");
const R = require("ramda");
const semver = require("semver");
const modulesController_1 = require("../fs/modulesController");
const realNodeModulesDir_1 = require("../fs/realNodeModulesDir");
const getPkgInfoFromShr_1 = require("../getPkgInfoFromShr");
const postInstall_1 = require("../install/postInstall");
const extendRebuildOptions_1 = require("./extendRebuildOptions");
const getContext_1 = require("./getContext");
function getPackagesInfo(packages, idsToRebuild) {
    return idsToRebuild
        .map((relativeDepPath) => {
        const pkgShr = packages[relativeDepPath];
        const pkgInfo = getPkgInfoFromShr_1.default(relativeDepPath, pkgShr);
        return {
            name: pkgInfo.name,
            pkgShr,
            relativeDepPath,
            version: pkgInfo.version,
        };
    })
        .filter((pkgInfo) => {
        if (!pkgInfo.name) {
            logger_1.default.warn(`Skipping ${pkgInfo.relativeDepPath} because cannot get the package name from shrinkwrap.yaml.
          Try to run run \`pnpm update --depth 100\` to create a new shrinkwrap.yaml with all the necessary info.`);
            return false;
        }
        return true;
    });
}
function rebuildPkgs(pkgSpecs, maybeOpts) {
    return __awaiter(this, void 0, void 0, function* () {
        const reporter = maybeOpts && maybeOpts.reporter;
        if (reporter) {
            logger_1.streamParser.on('data', reporter);
        }
        const opts = yield extendRebuildOptions_1.default(maybeOpts);
        const ctx = yield getContext_1.default(opts);
        const modules = yield realNodeModulesDir_1.default(opts.prefix);
        if (!ctx.currentShrinkwrap || !ctx.currentShrinkwrap.packages)
            return;
        const packages = ctx.currentShrinkwrap.packages;
        const searched = pkgSpecs.map((arg) => {
            const parsed = npa(arg);
            if (parsed.raw === parsed.name) {
                return parsed.name;
            }
            if (parsed.type !== 'version' && parsed.type !== 'range') {
                throw new Error(`Invalid argument - ${arg}. Rebuild can only select by version or range`);
            }
            return {
                name: parsed.name,
                range: parsed.fetchSpec,
            };
        });
        const pkgs = getPackagesInfo(packages, R.keys(packages))
            .filter((pkg) => matches(searched, pkg));
        yield _rebuild(pkgs, modules, ctx.currentShrinkwrap.registry, opts);
    });
}
exports.rebuildPkgs = rebuildPkgs;
// TODO: move this logic to separate package as this is also used in dependencies-hierarchy
function matches(searched, pkg) {
    return searched.some((searchedPkg) => {
        if (typeof searchedPkg === 'string') {
            return pkg.name === searchedPkg;
        }
        return searchedPkg.name === pkg.name && !!pkg.version &&
            semver.satisfies(pkg.version, searchedPkg.range);
    });
}
function rebuild(maybeOpts) {
    return __awaiter(this, void 0, void 0, function* () {
        const reporter = maybeOpts && maybeOpts.reporter;
        if (reporter) {
            logger_1.streamParser.on('data', reporter);
        }
        const opts = yield extendRebuildOptions_1.default(maybeOpts);
        const ctx = yield getContext_1.default(opts);
        const modules = yield realNodeModulesDir_1.default(opts.prefix);
        let idsToRebuild = [];
        if (opts.pending) {
            idsToRebuild = ctx.pendingBuilds;
        }
        else if (ctx.currentShrinkwrap && ctx.currentShrinkwrap.packages) {
            idsToRebuild = R.keys(ctx.currentShrinkwrap.packages);
        }
        else {
            return;
        }
        const pkgs = getPackagesInfo(ctx.currentShrinkwrap.packages || {}, idsToRebuild);
        yield _rebuild(pkgs, modules, ctx.currentShrinkwrap.registry, opts);
        yield modulesController_1.save(path.join(ctx.root, 'node_modules'), {
            hoistedAliases: ctx.hoistedAliases,
            independentLeaves: opts.independentLeaves,
            layoutVersion: modulesController_1.LAYOUT_VERSION,
            packageManager: `${opts.packageManager.name}@${opts.packageManager.version}`,
            pendingBuilds: [],
            shamefullyFlatten: opts.shamefullyFlatten,
            skipped: Array.from(ctx.skipped),
            store: ctx.storePath,
        });
    });
}
exports.rebuild = rebuild;
function _rebuild(pkgs, modules, registry, opts) {
    return __awaiter(this, void 0, void 0, function* () {
        yield pSeries(pkgs
            .map((pkgToRebuild) => () => __awaiter(this, void 0, void 0, function* () {
            const depAbsolutePath = dp.resolve(registry, pkgToRebuild.relativeDepPath);
            const pkgId = pkgToRebuild.pkgShr.id || depAbsolutePath;
            try {
                yield postInstall_1.default(path.join(modules, `.${depAbsolutePath}`, 'node_modules', pkgToRebuild.name), {
                    initialWD: opts.prefix,
                    pkgId,
                    rawNpmConfig: opts.rawNpmConfig,
                    unsafePerm: opts.unsafePerm || false,
                    userAgent: opts.userAgent,
                });
            }
            catch (err) {
                if (pkgToRebuild.pkgShr.optional) {
                    logger_1.default.warn({
                        err,
                        message: `Skipping failed optional dependency ${pkgId}`,
                    });
                    return;
                }
                throw err;
            }
        })));
    });
}
//# sourceMappingURL=rebuild.js.map