"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    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) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __rest = (this && this.__rest) || function (s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.NpmController = void 0;
const child_process_promise_1 = require("child-process-promise");
const system_settings_1 = require("@ewizardjs/system-settings");
const fs_extra_1 = require("fs-extra");
const path_1 = require("path");
const ramda_1 = require("ramda");
const url_1 = require("url");
const utils_1 = require("../../utils");
const urlJoin = require("url-join");
const Logger_1 = require("../Logger");
const I18n_1 = require("../I18n");
const NPM_RC = {
    project: '.npmrc',
    builtIn: 'npmrc',
};
const LOCKFILE_VERSIONS = {
    [system_settings_1.NpmVersion.Legacy]: 1,
    [system_settings_1.NpmVersion.Latest]: 3,
};
class NpmController {
    constructor(_a) {
        var { cwd, registry = '', token = '', npmVersion = system_settings_1.NpmVersion.Latest, distTag } = _a, options = __rest(_a, ["cwd", "registry", "token", "npmVersion", "distTag"]);
        const env = (0, ramda_1.compose)((0, ramda_1.mergeLeft)({ AUTH_TOKEN: token }), removeNpmConfigOptions)(process.env);
        this.npmVersion = npmVersion;
        this.registry = registry;
        this.distTag = distTag;
        this.options = Object.assign(Object.assign({}, options), { cwd,
            env });
        this.setNpmPaths();
    }
    install(args) {
        return __awaiter(this, void 0, void 0, function* () {
            if (this.npmVersion === system_settings_1.NpmVersion.Legacy) {
                yield this.installWithNpmLegacy(args);
            }
            else {
                yield this.installWithNpmLatest(args);
            }
        });
    }
    installWithNpmLegacy(args) {
        return __awaiter(this, void 0, void 0, function* () {
            const { options } = this;
            const updateLockFileCommand = yield this.getUpdateLockFileCommand();
            yield this.runNpm([
                ...updateLockFileCommand,
                { cmd: 'i', args: ['--package-lock-only', ...args], options },
                { cmd: 'ci', args: [], options },
            ]);
        });
    }
    installWithNpmLatest(args) {
        return __awaiter(this, void 0, void 0, function* () {
            const { options } = this;
            const updateLockFileCommand = yield this.getUpdateLockFileCommand();
            const cmd = !args.length && (yield (0, utils_1.isPackageLockFileAvailable)(options.cwd)) ? 'ci' : 'i';
            yield this.runNpm([
                ...updateLockFileCommand,
                { cmd, args: ['--legacy-peer-deps', ...args], options },
            ]);
        });
    }
    publish() {
        return __awaiter(this, void 0, void 0, function* () {
            const { distTag, options } = this;
            const args = [];
            if (distTag) {
                args.push(`--tag=${distTag}`);
            }
            yield this.runNpm([{ cmd: 'publish', args, options }]);
        });
    }
    uninstall(args) {
        return __awaiter(this, void 0, void 0, function* () {
            const { options } = this;
            if (this.npmVersion === system_settings_1.NpmVersion.Latest) {
                args.push('--legacy-peer-deps');
            }
            yield this.runNpm([{ cmd: 'r', args, options }]);
        });
    }
    setNpmPaths() {
        this.npmPaths = this.getNpmPaths();
        this.npmRcPaths = this.getNpmRcPaths();
    }
    getNpmPaths() {
        const pathEntries = Object
            .values(system_settings_1.NpmVersion)
            .map((npmVersion) => [npmVersion, (0, utils_1.getNpm)({ npmVersion })]);
        return Object.fromEntries(pathEntries);
    }
    getNpmRcPaths() {
        const builtInConfigs = Object
            .values(system_settings_1.NpmVersion)
            .map((npmVersion) => (0, path_1.join)((0, utils_1.getNpm)({ npmVersion, root: true }), NPM_RC.builtIn));
        const projectConfig = (0, path_1.join)(this.options.cwd, NPM_RC.project);
        return [...builtInConfigs, projectConfig];
    }
    runNpm(npmCommands) {
        return __awaiter(this, void 0, void 0, function* () {
            if (this.registry) {
                yield this.runNpmWithRc(npmCommands);
            }
            else {
                yield this.runNpmCommands(npmCommands);
            }
        });
    }
    runNpmWithRc(npmCommands) {
        return __awaiter(this, void 0, void 0, function* () {
            try {
                yield this.createNpmRc();
                yield this.runNpmCommands(npmCommands);
            }
            finally {
                yield this.removeNpmRc();
            }
        });
    }
    runNpmCommands(npmCommands) {
        return __awaiter(this, void 0, void 0, function* () {
            for (const command of npmCommands) {
                yield this.runNpmProcess(command);
            }
        });
    }
    createNpmRc() {
        const content = this.generateNpmConfig();
        return Promise.all(this.npmRcPaths.map((path) => (0, fs_extra_1.outputFile)(path, content)));
    }
    removeNpmRc() {
        return Promise.all(this.npmRcPaths.map((path) => (0, fs_extra_1.remove)(path)));
    }
    generateNpmConfig() {
        const { host, pathname } = (0, url_1.parse)(this.registry);
        const ewizardjsNamespace = '@ewizardjs';
        const registry = `registry=${this.registry}`;
        const registryWithoutProtocol = urlJoin(host, removeTrailingSlash(pathname));
        return `${ewizardjsNamespace}:${registry}\n${registry}\n//${registryWithoutProtocol}/:always-auth=true\n//${registryWithoutProtocol}/:_authToken=\${AUTH_TOKEN}`;
    }
    runNpmProcess({ cmd, args, npmVersion = this.npmVersion, options }) {
        return __awaiter(this, void 0, void 0, function* () {
            const npm = this.npmPaths[npmVersion];
            Logger_1.default.info(I18n_1.default.info('NPM_VERSION_IS', npmVersion));
            yield (0, child_process_promise_1.fork)(npm, [cmd, ...args], options);
        });
    }
    getUpdateLockFileCommand() {
        return __awaiter(this, void 0, void 0, function* () {
            const { options } = this;
            const npmVersion = system_settings_1.NpmVersion.Latest;
            const packageLock = yield (0, utils_1.getPackageLockFile)(options.cwd);
            const targetLockfileVersion = LOCKFILE_VERSIONS[this.npmVersion];
            return packageLock && packageLock.lockfileVersion !== targetLockfileVersion
                ? [{
                        cmd: 'i',
                        args: ['--legacy-peer-deps', '--lockfile-version', targetLockfileVersion.toString()],
                        npmVersion,
                        options,
                    }]
                : [];
        });
    }
}
exports.NpmController = NpmController;
function removeTrailingSlash(pathname) {
    return pathname.replace(/\/$/, '');
}
function removeNpmConfigOptions(obj) {
    return (0, ramda_1.omit)(['npm_config_registry', 'npm_config_always_auth'], obj);
}
//# sourceMappingURL=index.js.map