UNPKG

@oclif/plugin-plugins

Version:
150 lines (147 loc) 6.86 kB
"use strict"; var _a; Object.defineProperty(exports, "__esModule", { value: true }); const core_1 = require("@oclif/core"); const validate = require("validate-npm-package-name"); const chalk = require("chalk"); const plugins_1 = require("../../plugins"); class PluginsInstall extends core_1.Command { constructor() { super(...arguments); this.plugins = new plugins_1.default(this.config); } // In this case we want these operations to happen // sequentially so the `no-await-in-loop` rule is ignored /* eslint-disable no-await-in-loop */ async run() { const { flags, argv } = await this.parse(PluginsInstall); this.flags = flags; if (flags.verbose) this.plugins.verbose = true; const aliases = this.config.pjson.oclif.aliases || {}; for (let name of argv) { if (aliases[name] === null) this.error(`${name} is blocked`); name = aliases[name] || name; const p = await this.parsePlugin(name); let plugin; await this.config.runHook('plugins:preinstall', { plugin: p, }); try { if (p.type === 'npm') { core_1.ux.action.start(`Installing plugin ${chalk.cyan(this.plugins.friendlyName(p.name) + '@' + p.tag)}`); plugin = await this.plugins.install(p.name, { tag: p.tag, force: flags.force, }); } else { core_1.ux.action.start(`Installing plugin ${chalk.cyan(p.url)}`); plugin = await this.plugins.install(p.url, { force: flags.force }); } } catch (error) { core_1.ux.action.stop(chalk.bold.red('failed')); throw error; } core_1.ux.action.stop(`installed v${plugin.version}`); } } /* eslint-enable no-await-in-loop */ async parsePlugin(input) { // git ssh url if (input.startsWith('git+ssh://') || input.endsWith('.git')) { return { url: input, type: 'repo' }; } const getNameAndTag = async (input) => { var _b, _c; const regexAtSymbolNotAtBeginning = /(?<!^)@/; const [splitName, tag = 'latest'] = input.split(regexAtSymbolNotAtBeginning); const name = splitName.startsWith('@') ? splitName : await this.plugins.maybeUnfriendlyName(splitName); validateNpmPkgName(name); if (this.flags.jit) { const jitVersion = (_c = (_b = this.config.pjson.oclif) === null || _b === void 0 ? void 0 : _b.jitPlugins) === null || _c === void 0 ? void 0 : _c[name]; if (jitVersion) { if (regexAtSymbolNotAtBeginning.test(input)) this.warn(`--jit flag is present along side a tag. Ignoring tag ${tag} and using the version specified in package.json (${jitVersion}).`); return { name, tag: jitVersion }; } this.warn(`--jit flag is present but ${name} is not a JIT plugin. Installing ${tag} instead.`); return { name, tag }; } return { name, tag }; }; // scoped npm package, e.g. @oclif/plugin-version if (input.startsWith('@') && input.includes('/')) { const { name, tag } = await getNameAndTag(input); return { name, tag, type: 'npm' }; } if (input.includes('/')) { // github url, e.g. https://github.com/oclif/plugin-version if (input.includes(':')) return { url: input, type: 'repo' }; // github org/repo, e.g. oclif/plugin-version return { url: `https://github.com/${input}`, type: 'repo' }; } // unscoped npm package, e.g. my-oclif-plugin // friendly plugin name, e.g. version instead of @oclif/plugin-version (requires `scope` to be set in root plugin's package.json) const { name, tag } = await getNameAndTag(input); return { name, tag, type: 'npm' }; } } exports.default = PluginsInstall; _a = PluginsInstall; PluginsInstall.description = `Installs a plugin into the CLI. Can be installed from npm or a git url. Installation of a user-installed plugin will override a core plugin. e.g. If you have a core plugin that has a 'hello' command, installing a user-installed plugin with a 'hello' command will override the core plugin implementation. This is useful if a user needs to update core plugin functionality in the CLI without the need to patch and update the whole CLI. `; PluginsInstall.usage = 'plugins:install PLUGIN...'; PluginsInstall.examples = [ '$ <%= config.bin %> plugins:install <%- config.pjson.oclif.examplePlugin || "myplugin" %> ', '$ <%= config.bin %> plugins:install https://github.com/someuser/someplugin', '$ <%= config.bin %> plugins:install someuser/someplugin', ]; PluginsInstall.strict = false; PluginsInstall.args = { plugin: core_1.Args.string({ description: 'Plugin to install.', required: true }), }; PluginsInstall.flags = { help: core_1.Flags.help({ char: 'h' }), verbose: core_1.Flags.boolean({ char: 'v' }), force: core_1.Flags.boolean({ char: 'f', description: 'Run yarn install with force flag.', }), jit: core_1.Flags.boolean({ hidden: true, parse: async (input, ctx) => { var _b; if (input === false || input === undefined) return input; const requestedPlugins = ctx.argv.filter(a => !a.startsWith('-')); if (requestedPlugins.length === 0) return input; const jitPluginsConfig = (_b = ctx.config.pjson.oclif.jitPlugins) !== null && _b !== void 0 ? _b : {}; if (Object.keys(jitPluginsConfig).length === 0) return input; const plugins = new plugins_1.default(ctx.config); const nonJitPlugins = await Promise.all(requestedPlugins.map(async (plugin) => { const name = await plugins.maybeUnfriendlyName(plugin); return { name, jit: Boolean(jitPluginsConfig[name]) }; })); const nonJitPluginsNames = nonJitPlugins.filter(p => !p.jit).map(p => p.name); if (nonJitPluginsNames.length > 0) { throw new core_1.Errors.CLIError(`The following plugins are not JIT plugins: ${nonJitPluginsNames.join(', ')}`); } return input; }, }), }; PluginsInstall.aliases = ['plugins:add']; function validateNpmPkgName(name) { if (!validate(name).validForNewPackages) { throw new core_1.Errors.CLIError('Invalid npm package name.'); } }