diff --git a/clients/js/.eslintrc.cjs b/clients/js/.eslintrc.cjs index ec6bf1e..f68a5b6 100644 --- a/clients/js/.eslintrc.cjs +++ b/clients/js/.eslintrc.cjs @@ -1,6 +1,11 @@ module.exports = { extends: ['@solana/eslint-config-solana'], - ignorePatterns: ['.eslintrc.cjs', 'tsup.config.ts', 'env-shim.ts'], + ignorePatterns: [ + '.eslintrc.cjs', + 'tsup.config.ts', + 'env-shim.ts', + 'bin/cli.cjs', + ], parserOptions: { project: 'tsconfig.json', tsconfigRootDir: __dirname, diff --git a/clients/js/bin/cli.cjs b/clients/js/bin/cli.cjs new file mode 100755 index 0000000..35ffceb --- /dev/null +++ b/clients/js/bin/cli.cjs @@ -0,0 +1,5 @@ +#!/usr/bin/env -S node + +const run = require('../dist/src/cli.js').run; + +run(process.argv); diff --git a/clients/js/package.json b/clients/js/package.json index 9e6cce9..6a76ba9 100644 --- a/clients/js/package.json +++ b/clients/js/package.json @@ -15,7 +15,7 @@ } }, "bin": { - "program-metadata": "./dist/src/cli.js" + "program-metadata": "./bin/cli.cjs" }, "files": [ "./dist/src", diff --git a/clients/js/src/cli/index.ts b/clients/js/src/cli/index.ts index 2851943..be6b023 100644 --- a/clients/js/src/cli/index.ts +++ b/clients/js/src/cli/index.ts @@ -1 +1,16 @@ -export * from './program'; +import { logDebug, logError } from './logs'; +import { createProgram } from './program'; + +const program = createProgram(); + +export async function run(argv: readonly string[]) { + try { + await program.parseAsync(argv); + } catch (err) { + if (program.opts().debug) { + logDebug(`${(err as { stack: string }).stack}`); + } + logError((err as { message: string }).message); + process.exitCode = 1; + } +} diff --git a/clients/js/src/cli/logs.ts b/clients/js/src/cli/logs.ts index 75e7f75..063e77c 100644 --- a/clients/js/src/cli/logs.ts +++ b/clients/js/src/cli/logs.ts @@ -59,6 +59,10 @@ export function logError(message: string): void { console.error(picocolors.red(`[Error] `) + message); } +export function logDebug(message: string): void { + console.debug(picocolors.magenta(`[Debug] `) + message); +} + export function logErrorAndExit(message: string): never { logError(message); process.exit(1); diff --git a/clients/js/src/cli/program.ts b/clients/js/src/cli/program.ts index 88b57df..676151e 100644 --- a/clients/js/src/cli/program.ts +++ b/clients/js/src/cli/program.ts @@ -1,16 +1,40 @@ -#!/usr/bin/env node - import { setCommands } from './commands'; import { setGlobalOptions } from './options'; import { CustomCommand } from './utils'; -// Define the CLI program. -const program = new CustomCommand(); -program - .name('program-metadata') - .description('CLI to manage Solana program metadata and IDLs') - .version(__VERSION__) - .configureHelp({ showGlobalOptions: true }) - .tap(setGlobalOptions) - .tap(setCommands) - .parse(); +export async function programMetadata( + args: string[], + opts?: { suppressOutput?: boolean } +): Promise { + await createProgram({ + exitOverride: true, + suppressOutput: opts?.suppressOutput, + }).parseAsync(args, { from: 'user' }); +} + +export function createProgram(internalOptions?: { + exitOverride?: boolean; + suppressOutput?: boolean; +}): CustomCommand { + const program = new CustomCommand(); + program + .name('program-metadata') + .description('CLI to manage Solana program metadata and IDLs') + .version(__VERSION__) + .configureHelp({ showGlobalOptions: true }) + .tap(setGlobalOptions) + .tap(setCommands); + + // Internal options. + if (internalOptions?.exitOverride) { + program.exitOverride(); + } + if (internalOptions?.suppressOutput) { + program.configureOutput({ + writeErr: () => {}, + writeOut: () => {}, + }); + } + + return program; +}