diff --git a/bin/dev.js b/bin/dev.js index f51631f..5e8ddd8 100755 --- a/bin/dev.js +++ b/bin/dev.js @@ -1,23 +1,16 @@ #!/usr/bin/env node_modules/.bin/ts-node -const PROVISIONING = true; +const OCLIF_PATCH = true +const COMMAND_PATCH_ENABLED = true // eslint-disable-next-line node/shebang, unicorn/prefer-top-level-await ; (async () => { - const oclif = await import('@oclif/core') + const oclif = OCLIF_PATCH ? require('../src/patches/oclif/execute') : await import('@oclif/core') // Check Provisioning commands - if (PROVISIONING) require('../src/patches/provisioning').checkProvisioningCommand(process.argv) + if (COMMAND_PATCH_ENABLED) require('../src/patches/command').patchCommand(process.argv) await oclif.execute({ development: true, dir: __dirname }) - .then(oclif.flush(60000)) - .catch(error => { - if (error.code === 'EEXIT' && error.oclif.exit === 0) { /* command exit (quit) */ } - else - if (error.message === 'HOOK_EXIT') { /* hook exit */ } - else - return oclif.Errors.handle(error) - }) -})() \ No newline at end of file +})() diff --git a/bin/run.js b/bin/run.js index 4a1d43e..047ca56 100755 --- a/bin/run.js +++ b/bin/run.js @@ -1,23 +1,16 @@ #!/usr/bin/env node -const PROVISIONING = true; +const OCLIF_PATCH = true +const COMMAND_PATCH_ENABLED = true // eslint-disable-next-line unicorn/prefer-top-level-await -(async () => { +; (async () => { - const oclif = await import('@oclif/core') + const oclif = OCLIF_PATCH ? require('../lib/patches/oclif/execute') : await import('@oclif/core') // Check Provisioning commands - if (PROVISIONING) require('../lib/patches/provisioning').checkProvisioningCommand(process.argv) + if (COMMAND_PATCH_ENABLED) require('../lib/patches/command').patchCommand(process.argv) await oclif.execute({ development: false, dir: __dirname }) - .then(oclif.flush(60000)) - .catch(error => { - if (error.code === 'EEXIT' && error.oclif.exit === 0) { /* command exit (quit) */ } - else - if (error.message === 'HOOK_EXIT') { /* hook exit */ } - else - return oclif.Errors.handle(error) - }) })() \ No newline at end of file diff --git a/src/commands/plugins/available.ts b/src/commands/plugins/available.ts index 45a6b65..1901968 100644 --- a/src/commands/plugins/available.ts +++ b/src/commands/plugins/available.ts @@ -105,7 +105,7 @@ const getInstalledPlugins = (config: Config): PluginRelease[] => { const isPluginInstalled = (name: string, config: Config): boolean => { const plugin = name.startsWith(PLUGIN_PREFIX)? name : `${PLUGIN_PREFIX}${name}` - return (getInstalledPlugins(config).findIndex(p => (p.name === name) || (p.name === plugin)) > -1) + return (getInstalledPlugins(config).findIndex(p => (p.plugin === plugin)) > -1) } diff --git a/src/hooks/prerun/plugin.ts b/src/hooks/prerun/plugin.ts index 6b4dea3..72ab62c 100644 --- a/src/hooks/prerun/plugin.ts +++ b/src/hooks/prerun/plugin.ts @@ -1,6 +1,6 @@ import { clColor, clOutput } from '@commercelayer/cli-core' import type { Hook } from '@oclif/core' -import { getAvailablePlugins, getInstalledPlugins, getPluginInfo } from '../../commands/plugins/available' +import { getAvailablePlugins, getInstalledPlugins, getPluginInfo, isPluginInstalled } from '../../commands/plugins/available' import inquirer from 'inquirer' import type { Config } from '@oclif/core/lib/interfaces' import { CLIError } from '@oclif/core/lib/errors' @@ -32,6 +32,7 @@ const hook: Hook<'prerun'> = async function (opts) { let index = -1 let plugin + let pluginArg const found = opts.argv.some(a => { @@ -39,7 +40,8 @@ const hook: Hook<'prerun'> = async function (opts) { if (a.startsWith('-')) return false // ignore flags if (opts.argv[index - 1] === '--tag') return false // ignore --tag value - const p = getPluginInfo(a) + pluginArg = a + const p = getPluginInfo(pluginArg) if (p === undefined) this.error(`Unknown Commerce Layer CLI plugin: ${clColor.msg.error(a)}. Run '${clColor.italic(`${this.config.bin} plugins:available`)}' to get a list of all available plugins`) else plugin = p.plugin @@ -50,10 +52,21 @@ const hook: Hook<'prerun'> = async function (opts) { if (found && plugin) { - // Check tag flag + let errMsg: string = '' + if ((command === 'install') && isPluginInstalled(plugin, this.config)) errMsg = 'Commerce Layer CLI plugin already installed' + else + if ((command === 'uninstall') && !isPluginInstalled(plugin, this.config)) errMsg = 'Commerce Layer CLI plugin not installed' + + if (errMsg) { + this.log(`\n${errMsg}: ${clColor.cli.plugin(pluginArg)}\n`) + throw new CLIError('HOOK_EXIT') + } else this.log('') + + + // Check tag flag const tgIndex = opts.argv.indexOf('--tag') if (tgIndex > -1) { - plugin =`${plugin}@${opts.argv[tgIndex + 1]}` + plugin = `${plugin}@${opts.argv[tgIndex + 1]}` opts.argv.splice(tgIndex, 2) } @@ -74,22 +87,22 @@ const promptPlugin = async (config: Config, command: string): Promise => if (plugins.length === 0) return '' - const plgMaxLength = clOutput.maxLength(plugins, 'name') + 4 + const plgMaxLength = clOutput.maxLength(plugins, 'name') + 4 plugins.sort((a, b) => a.name.localeCompare(b.name)) - const answers = await inquirer.prompt([{ - type: 'list', - name: 'plugin', - message: `Select a plugin to ${command}:`, - choices: plugins.map(p => { - return { name: `${p.name.padEnd(plgMaxLength, ' ')} ${clColor.italic(p.description)}`, value: p.plugin } - }), - loop: false, - pageSize: 10, - }]) - - return answers.plugin as string + const answers = await inquirer.prompt([{ + type: 'list', + name: 'plugin', + message: `Select a plugin to ${command}:`, + choices: plugins.map(p => { + return { name: `${p.name.padEnd(plgMaxLength, ' ')} ${clColor.italic(p.description)}`, value: p.plugin } + }), + loop: false, + pageSize: 10, + }]) + + return answers.plugin as string } diff --git a/src/patches/command.ts b/src/patches/command.ts new file mode 100644 index 0000000..2e37b98 --- /dev/null +++ b/src/patches/command.ts @@ -0,0 +1,46 @@ + +import { clText } from "@commercelayer/cli-core" +import { CommerceLayerProvisioningStatic } from "@commercelayer/provisioning-sdk" + + +const PROVISIONING = true +const provisioningCommands = ['retrieve', 'list', 'create', 'update', 'delete', 'get', 'relationship', 'fetch'] + + +export const patchCommand = (argv: string[]): string[] => { + + const cmdIdx = process.argv.findIndex(a => !a.startsWith('/')) + const cmd = process.argv[cmdIdx] + + // Check provisioning command + if (PROVISIONING && provisioningCommands.includes(cmd)) return checkProvisioningCommand(cmd, cmdIdx, argv) + + // Check plugins command + if (['install', 'uninstall'].includes(cmd)) argv[cmdIdx] = `plugins:${cmd}` + + + return argv + +} + + +export const checkProvisioningCommand = (cmd: string, cmdIdx: number, argv: string[]): string[] => { + + const res = process.argv.find(a => !a.startsWith('/') && (a !== cmd)) + + // Check provisioning resource + if (res) { + + const provisioningResources = [...CommerceLayerProvisioningStatic.resources()] + provisioningResources.splice(provisioningResources.indexOf('organizations'), 1) + provisioningResources.splice(provisioningResources.indexOf('versions'), 1) + + const provisioningResource = provisioningResources.includes(res) || (provisioningResources.includes(clText.pluralize(res))) + if (provisioningResource) process.argv[cmdIdx] = `provisioning:${cmd}` + + } + + + return argv + +} diff --git a/src/patches/oclif/execute.ts b/src/patches/oclif/execute.ts new file mode 100644 index 0000000..0b09446 --- /dev/null +++ b/src/patches/oclif/execute.ts @@ -0,0 +1,29 @@ +import { run, handle, flush, settings} from '@oclif/core' +import type { LoadOptions } from '@oclif/core/lib/interfaces' + + +export async function execute(options: { + args?: string[] + development?: boolean + dir: string + loadOptions?: LoadOptions +}): Promise { + + if (options.development) { + process.env.NODE_ENV = 'development' + settings.debug = true + } + + return run(options.args ?? process.argv.slice(2), options.loadOptions ?? options.dir) + .then(async (result) => { + await flush(60000) + return result + }) + .catch(async (error) => { + if (error.code === 'EEXIT' && error.oclif.exit === 0) { /* command exit (quit) */ } + else + if (error.message === 'HOOK_EXIT') { /* hook exit */ } + else return handle(error as Error) + }) + +} diff --git a/src/patches/provisioning.ts b/src/patches/provisioning.ts deleted file mode 100644 index 8fee455..0000000 --- a/src/patches/provisioning.ts +++ /dev/null @@ -1,35 +0,0 @@ - -import { clText } from "@commercelayer/cli-core" -import { CommerceLayerProvisioningStatic } from "@commercelayer/provisioning-sdk" - - -const provisioningCommands = ['retrieve', 'list', 'create', 'update', 'delete', 'get', 'relationship', 'fetch'] - - -export const checkProvisioningCommand = (argv: string[]): string[] => { - - const cmdIdx = process.argv.findIndex(a => !a.startsWith('/')) - const cmd = process.argv[cmdIdx] - - // Check provisioning command - if (provisioningCommands.includes(cmd)) { - - const res = process.argv.find(a => !a.startsWith('/') && (a !== cmd)) - - // Check provisioning resource - if (res) { - - const provisioningResources = [ ...CommerceLayerProvisioningStatic.resources() ] - provisioningResources.splice(provisioningResources.indexOf('organizations'), 1) - provisioningResources.splice(provisioningResources.indexOf('versions'), 1) - - const provisioningResource = provisioningResources.includes(res) || (provisioningResources.includes(clText.pluralize(res))) - if (provisioningResource) process.argv[cmdIdx] = `provisioning:${cmd}` - - } - - } - - return argv - -}