1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3    return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5Object.defineProperty(exports, "__esModule", { value: true });
6exports.NpmPackageManager = void 0;
7const json_file_1 = __importDefault(require("@expo/json-file"));
8const npm_package_arg_1 = __importDefault(require("npm-package-arg"));
9const path_1 = __importDefault(require("path"));
10const BasePackageManager_1 = require("./BasePackageManager");
11const nodeWorkspaces_1 = require("../utils/nodeWorkspaces");
12const spawn_1 = require("../utils/spawn");
13class NpmPackageManager extends BasePackageManager_1.BasePackageManager {
14    name = 'npm';
15    bin = 'npm';
16    lockFile = nodeWorkspaces_1.NPM_LOCK_FILE;
17    workspaceRoot() {
18        const root = (0, nodeWorkspaces_1.findYarnOrNpmWorkspaceRoot)(this.ensureCwdDefined('workspaceRoot'));
19        if (root) {
20            return new NpmPackageManager({
21                ...this.options,
22                silent: this.silent,
23                log: this.log,
24                cwd: root,
25            });
26        }
27        return null;
28    }
29    addAsync(namesOrFlags = []) {
30        if (!namesOrFlags.length) {
31            return this.installAsync();
32        }
33        const { flags, versioned, unversioned } = this.parsePackageSpecs(namesOrFlags);
34        return (0, spawn_1.createPendingSpawnAsync)(() => this.updatePackageFileAsync(versioned, 'dependencies'), () => !unversioned.length
35            ? this.runAsync(['install', ...flags])
36            : this.runAsync(['install', '--save', ...flags, ...unversioned.map((spec) => spec.raw)]));
37    }
38    addDevAsync(namesOrFlags = []) {
39        if (!namesOrFlags.length) {
40            return this.installAsync();
41        }
42        const { flags, versioned, unversioned } = this.parsePackageSpecs(namesOrFlags);
43        return (0, spawn_1.createPendingSpawnAsync)(() => this.updatePackageFileAsync(versioned, 'devDependencies'), () => !unversioned.length
44            ? this.runAsync(['install', ...flags])
45            : this.runAsync([
46                'install',
47                '--save-dev',
48                ...flags,
49                ...unversioned.map((spec) => spec.raw),
50            ]));
51    }
52    addGlobalAsync(namesOrFlags = []) {
53        if (!namesOrFlags.length) {
54            return this.installAsync();
55        }
56        return this.runAsync(['install', '--global', ...namesOrFlags]);
57    }
58    removeAsync(namesOrFlags) {
59        return this.runAsync(['uninstall', ...namesOrFlags]);
60    }
61    removeDevAsync(namesOrFlags) {
62        return this.runAsync(['uninstall', '--save-dev', ...namesOrFlags]);
63    }
64    removeGlobalAsync(namesOrFlags) {
65        return this.runAsync(['uninstall', '--global', ...namesOrFlags]);
66    }
67    /**
68     * Parse all package specifications from the names or flag list.
69     * The result from this method can be used for `.updatePackageFileAsync`.
70     */
71    parsePackageSpecs(namesOrFlags) {
72        const result = { flags: [], versioned: [], unversioned: [] };
73        namesOrFlags
74            .map((name) => {
75            if (name.trim().startsWith('-')) {
76                result.flags.push(name);
77                return null;
78            }
79            return (0, npm_package_arg_1.default)(name);
80        })
81            .forEach((spec) => {
82            // When using a dist-tag version of a library, we need to consider it as "unversioned".
83            // Doing so will install that version with `npm install --save(-dev)`, and resolve the dist-tag properly.
84            if (spec && spec.rawSpec && spec.type !== 'tag') {
85                result.versioned.push(spec);
86            }
87            else if (spec) {
88                result.unversioned.push(spec);
89            }
90        });
91        return result;
92    }
93    /**
94     * Older npm versions have issues with mismatched nested dependencies when adding exact versions.
95     * This propagates as issues like mismatched `@expo/config-pugins` versions.
96     * As a workaround, we update the `package.json` directly and run `npm install`.
97     */
98    async updatePackageFileAsync(packageSpecs, packageType) {
99        if (!packageSpecs.length) {
100            return;
101        }
102        const pkgPath = path_1.default.join(this.options.cwd?.toString() || '.', 'package.json');
103        const pkg = await json_file_1.default.readAsync(pkgPath);
104        packageSpecs.forEach((spec) => {
105            pkg[packageType] = pkg[packageType] || {};
106            pkg[packageType][spec.name] = spec.rawSpec;
107        });
108        await json_file_1.default.writeAsync(pkgPath, pkg, { json5: false });
109    }
110}
111exports.NpmPackageManager = NpmPackageManager;
112//# sourceMappingURL=NpmPackageManager.js.map