🦁
Nest.js で CLI ベースの処理を定義する
導入
まずは、nest-commander を インストールします。
$ npm i nest-commander
CLI 用のモジュールを作成してください。
$ nest g module cli
src/commands/cli.module.ts
import {Module} from '@nestjs/common';
@Module({
imports: [
],
})
export class CliModule {
}
実行用のファイル、cli.ts
を作成します。
import { CommandFactory } from 'nest-commander';
import {CliModule} from "./src/commands/cli.module";
async function bootstrap() {
await CommandFactory.run(CliModule,[
"log", "error", "warn" , "debug", "verbose"
]);
}
bootstrap();
CommandFactory.run
の第2引数には、ログレベルが指定可能です。
アプリケーションの必要に応じて、必要な項目を指定してください(上記は全出力の例)。
ts-node cli.ts
で実行して以下の表示が得られれば準備は完了です。
% ts-node cli.ts --help
[Nest] 27150 - 03/21/2022, 6:14:49 PM LOG [NestFactory] Starting Nest application...
[Nest] 27150 - 03/21/2022, 6:14:49 PM LOG [InstanceLoader] CommandRootModule dependencies initialized +14ms
[Nest] 27150 - 03/21/2022, 6:14:49 PM LOG [InstanceLoader] CliModule dependencies initialized +0ms
[Nest] 27150 - 03/21/2022, 6:14:49 PM LOG [InstanceLoader] DiscoveryModule dependencies initialized +0ms
[Nest] 27150 - 03/21/2022, 6:14:49 PM LOG [InstanceLoader] CommandRunnerModule dependencies initialized +1ms
Usage: cli [options]
Options:
-h, --help display help for command
コマンドの追加
src/cli/commands/debug.command.ts
を以下の内容で作成します。
import { Command, CommandRunner, Option } from 'nest-commander';
interface BasicCommandOptions {
string?: string;
boolean?: boolean;
number?: number;
}
@Command({
name: 'debug',
description: 'A parameter parse'
})
export class DebugCommand implements CommandRunner {
constructor() {}
async run(
passedParam: string[],
options?: BasicCommandOptions,
): Promise<void> {
if (options?.boolean !== undefined && options?.boolean !== null) {
this.runWithBoolean(passedParam, options.boolean);
} else if (options?.number) {
this.runWithNumber(passedParam, options.number);
} else if (options?.string) {
this.runWithString(passedParam, options.string);
} else {
this.runWithNone(passedParam);
}
}
@Option({
flags: '-n, --number [number]',
description: 'A basic number parser',
})
parseNumber(val: string): number {
return Number(val);
}
@Option({
flags: '-s, --string [string]',
description: 'A string return',
})
parseString(val: string): string {
return val;
}
@Option({
flags: '-b, --boolean [boolean]',
description: 'A boolean parser',
})
parseBoolean(val: string): boolean {
return JSON.parse(val);
}
runWithString(param: string[], option: string): void {
console.log({ param, string: option });
}
runWithNumber(param: string[], option: number): void {
console.log({ param, number: option });
}
runWithBoolean(param: string[], option: boolean): void {
console.log({ param, boolean: option });
}
runWithNone(param: string[]): void {
console.log({ param });
}
}
CliModule の providers セクションに 上記のコマンドを追加し、
ts-node cli.ts basic --help
で以下の出力が得られれば成功です。。
% ts-node cli.ts basic --help
[Nest] 27327 - 03/21/2022, 6:27:03 PM LOG [NestFactory] Starting Nest application...
[Nest] 27327 - 03/21/2022, 6:27:03 PM LOG [InstanceLoader] CommandRootModule dependencies initialized +18ms
[Nest] 27327 - 03/21/2022, 6:27:03 PM LOG [InstanceLoader] CliModule dependencies initialized +1ms
[Nest] 27327 - 03/21/2022, 6:27:03 PM LOG [InstanceLoader] DiscoveryModule dependencies initialized +0ms
[Nest] 27327 - 03/21/2022, 6:27:03 PM LOG [InstanceLoader] CommandRunnerModule dependencies initialized +0ms
Usage: cli basic [options]
A parameter parse
Options:
-n, --number [number] A basic number parser
-s, --string [string] A string return
-b, --boolean [boolean] A boolean parser
-h, --help display help for command
コマンドにおける引数
コマンドの引数は @Command
デコレータで指定します。
処理の本体 run
にて 第一引数で配列の形式にて値を取得できます。
import { Command, CommandRunner, Option } from 'nest-commander';
@Command({
name: 'run',
arguments: '<task> <task2>',
options: { isDefault: true }
})
export class DebugCommand implements CommandRunner {
async run(
inputs: string[],
): Promise<void> {
console.log(inputs)
}
}
上記のコマンドは実行すると以下のような出力が得られます。
$ ts-node cli.ts run hoge fuga
[ 'hoge', 'fuga' ]
定義している分の引数が不足していると missing argument のエラーとなりますが、
定義している以上の引数が渡された場合、エラーにはならずそのまま inputs に入ってくるので注意が必要です。
$ ts-node cli.ts run hoge fuga piyo
[ 'hoge', 'fuga', 'piyo']
なお、得られる値は配列の形式ですが、それぞれに適切な名前を与えておくことで --help
上の表示がわかりやすくなります。
オプションの登録
オプションは @Option
デコレータで一つづつ定義します。
import { Command, CommandRunner, Option } from 'nest-commander';
@Command({
name: 'run',
})
export class DebugCommand implements CommandRunner {
async run(
inputs: string[],
options: {[key:string]:string}
): Promise<void> {
console.log(options)
}
@Option({
flags: '-n, --name <shell>',
description: 'A different shell to spawn than the default'
})
parseName(name: string) {
return name;
}
}
実行すると以下のような出力を得られます。
$ ts-node cli.ts run --name hoge
{ name: 'hoge' }
備考
Discussion