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