UNPKG

2.64 kBJavaScriptView Raw
1import { Errors, ux } from '@oclif/core';
2import makeDebug from 'debug';
3import { readFile } from 'node:fs/promises';
4import { createRequire } from 'node:module';
5import { join, sep } from 'node:path';
6import { spawn } from './spawn.js';
7const debug = makeDebug('@oclif/plugin-plugins:npm');
8export class NPM {
9 bin;
10 config;
11 logLevel;
12 constructor({ config, logLevel }) {
13 this.config = config;
14 this.logLevel = logLevel;
15 }
16 async exec(args = [], options) {
17 const bin = await this.findNpm();
18 debug('npm binary path', bin);
19 args.push(`--loglevel=${this.logLevel}`, '--no-fund');
20 if (this.config.npmRegistry)
21 args.push(`--registry=${this.config.npmRegistry}`);
22 if (options.logLevel !== 'notice' && options.logLevel !== 'silent') {
23 ux.stderr(`${options.cwd}: ${bin} ${args.join(' ')}`);
24 }
25 debug(`${options.cwd}: ${bin} ${args.join(' ')}`);
26 try {
27 const output = await spawn(bin, args, options);
28 debug('npm done');
29 return output;
30 }
31 catch (error) {
32 debug('npm error', error);
33 throw error;
34 }
35 }
36 async install(args, opts) {
37 const prod = opts.prod ? ['--omit', 'dev'] : [];
38 return this.exec(['install', ...args, ...prod, '--no-audit'], opts);
39 }
40 async uninstall(args, opts) {
41 return this.exec(['uninstall', ...args], opts);
42 }
43 async update(args, opts) {
44 return this.exec(['update', ...args], opts);
45 }
46 async view(args, opts) {
47 return this.exec(['view', ...args], { ...opts, logLevel: 'silent' });
48 }
49 /**
50 * Get the path to the npm CLI file.
51 * This will resolve npm to the pinned version in `@oclif/plugin-plugins/package.json` if it exists.
52 * Otherwise, it will use the globally installed npm.
53 *
54 * @returns The path to the `npm/bin/npm-cli.js` file.
55 */
56 async findNpm() {
57 if (this.bin)
58 return this.bin;
59 try {
60 const npmPjsonPath = createRequire(import.meta.url).resolve('npm/package.json');
61 const npmPjson = JSON.parse(await readFile(npmPjsonPath, { encoding: 'utf8' }));
62 const npmPath = npmPjsonPath.slice(0, Math.max(0, npmPjsonPath.lastIndexOf(sep)));
63 this.bin = join(npmPath, npmPjson.bin.npm);
64 }
65 catch {
66 const { default: which } = await import('which');
67 this.bin = await which('npm');
68 }
69 if (!this.bin) {
70 throw new Errors.CLIError('npm not found');
71 }
72 return this.bin;
73 }
74}