引数とフラグ
ターミナルにおけるコマンドの引数は、execute メソッドまたは関数の通常の引数です。これらは自動的にコマンドライン引数にマッピングされます。
パラメーターをオプショナルとしてマークすると、渡す必要はありません。デフォルト値がある場合も、渡す必要はありません。
型(string、number、union など)に応じて、渡された値は自動的にデシリアライズおよびバリデーションされます。
import { cli } from '@deepkit/app'; //関数 new App().command('test', (name: string) => { console.log('Hello', name); }); //クラス @cli.controller('test') class TestCommand { async execute(name: string) { console.log('Hello', name); } }
name パラメーターを指定せずにこのコマンドを実行すると、エラーが発生します:
$ ts-node app.ts test RequiredArgsError: Missing 1 required arg: name
--help を使用すると、必須の引数についての詳細情報が得られます:
$ ts-node app.ts test --help USAGE $ ts-node-script app.ts test NAME
name を引数として渡すと、コマンドが実行され、name が正しく渡されます。
$ ts-node app.ts test "beautiful world" Hello beautiful world
string、number、boolean、文字列リテラル、それらの union、およびそれらの配列といったすべてのプリミティブなパラメーター型は、自動的に CLI 引数として使用され、 自動的にバリデーションおよびデシリアライズされます。パラメーターの順序が CLI 引数の順序を決定します。パラメーターはいくつでも追加できます。
複雑なオブジェクト(interface、class、オブジェクトリテラル)が定義されると、それはサービスの依存関係として扱われ、 Dependency Injection Container がそれを解決しようとします。詳細については 依存性注入 の章を参照してください。
複数の値
配列として型付けされた引数は、残りのすべての位置引数を受け取ります。各値はデシリアライズされ、要素の型に対してバリデーションされます。
配列の後にある引数はその値を保持するため、cp <files...> <target> のようなコマンドも期待どおりに動作します。
new App().command('copy', (files: string[], target: string) => { console.log('copy', files, 'to', target); }); new App().command('delete', (ids: number[]) => { console.log('delete', ids); });
$ ts-node app.ts copy a.txt b.txt backup/ copy [ 'a.txt', 'b.txt' ] to backup/ $ ts-node app.ts delete 1 2 3 delete [ 1, 2, 3 ] $ ts-node app.ts delete 1 two Invalid value for argument ids: 1,two. Cannot convert two to number [type]
必須の配列引数には少なくとも 1 つの値が必要です。ids: number[] = [] のようにデフォルト値がある場合は、オプショナルになります。
フラグ
フラグは、コマンドに値を渡すもう 1 つの方法です。ほとんどの場合オプショナルですが、そうである必要はありません。Flag 型で修飾されたパラメーターは、--name value または --name=value で渡すことができます。
import { Flag } from '@deepkit/app'; //関数 new App().command('test', (id: number & Flag) => { console.log('id', name); }); //クラス class TestCommand { async execute(id: number & Flag) { console.log('id', id); } }
$ ts-node app.ts test --help USAGE $ ts-node app.ts test OPTIONS --id=id (required)
ヘルプ表示の「OPTIONS」で、--id フラグが必要であることがわかります。このフラグを正しく入力すると、コマンドはこの値を受け取ります。
$ ts-node app.ts test --id 23 id 23 $ ts-node app.ts test --id=23 id 23
Boolean フラグ
フラグには、値なしのフラグとしても使用できるという利点があります。例えば、特定の動作を有効にするためなどです。パラメーターがオプショナルな Boolean としてマークされると、この動作が有効になります。
import { Flag } from '@deepkit/app'; //関数 new App().command('test', (remove: boolean & Flag = false) => { console.log('delete?', remove); }); //クラス class TestCommand { async execute(remove: boolean & Flag = false) { console.log('delete?', remove); } }
$ ts-node app.ts test delete? false $ ts-node app.ts test --remove delete? true
複数のフラグ
同じフラグに複数の値を渡すには、フラグを配列としてマークします。
import { Flag } from '@deepkit/app'; //関数 new App().command('test', (id: number[] & Flag = []) => { console.log('ids', id); }); //クラス class TestCommand { async execute(id: number[] & Flag = []) { console.log('ids', id); } }
$ ts-node app.ts test ids: [] $ ts-node app.ts test --id 12 ids: [12] $ ts-node app.ts test --id 12 --id 23 ids: [12, 23]
1 文字のフラグ
フラグを 1 文字でも渡せるようにするには、Flag<{char: 'x'}> を使用します。
import { Flag } from '@deepkit/app'; //関数 new App().command('test', (output: string & Flag<{char: 'o'}>) => { console.log('output: ', output); }); //クラス class TestCommand { async execute(output: string & Flag<{char: 'o'}>) { console.log('output: ', output); } }
$ ts-node app.ts test --help USAGE $ ts-node app.ts test OPTIONS -o, --output=output (required) $ ts-node app.ts test --output test.txt output: test.txt $ ts-node app.ts test -o test.txt output: test.txt
オプショナル / デフォルト
メソッド/関数のシグネチャによって、どの引数やフラグがオプショナルかが定義されます。型システムでパラメーターがオプショナルであれば、ユーザーはそれを指定する必要はありません。
//関数 new App().command('test', (name?: string) => { console.log('Hello', name || 'nobody'); }); //クラス class TestCommand { async execute(name?: string) { console.log('Hello', name || 'nobody'); } }
$ ts-node app.ts test
Hello nobodyデフォルト値を持つパラメーターも同様です:
//関数 new App().command('test', (name: string = 'body') => { console.log('Hello', name); }); //クラス class TestCommand { async execute(name: string = 'body') { console.log('Hello', name); } }
$ ts-node app.ts test
Hello nobodyこれはフラグにも同様に適用されます。
シリアライズ / バリデーション
すべての引数とフラグは、その型に基づいて自動的にデシリアライズおよびバリデーションされ、追加の制約を付与することもできます。
そのため、コマンドラインインターフェイスはテキスト、つまり文字列に基づいているにもかかわらず、number として定義された引数は、コントローラー内では常に実際の数値であることが保証されます。
//関数 new App().command('test', (id: number) => { console.log('id', id, typeof id); }); //クラス class TestCommand { async execute(id: number) { console.log('id', id, typeof id); } }
$ ts-node app.ts test 123 id 123 number
追加の制約は、@deepkit/type の型アノテーションで定義できます。
import { Positive } from '@deepkit/type'; //関数 new App().command('test', (id: number & Positive) => { console.log('id', id, typeof id); }); //クラス class TestCommand { async execute(id: number & Positive) { console.log('id', id, typeof id); } }
id の Postive 型は、正の数のみが許可されることを示します。ユーザーが負の数を渡すと、コードはまったく実行されず、エラーメッセージが表示されます。
$ ts-node app.ts test -123 Validation error in id: Number needs to be positive [positive]
この非常に簡単に行える追加のバリデーションにより、コマンドは誤った入力に対してはるかに堅牢になります。詳細については バリデーション の章を参照してください。
説明
フラグや引数を説明するには、@description コメントデコレーターを使用します。
import { Positive } from '@deepkit/type'; class TestCommand { async execute( /** @description The users identifier */ id: number & Positive, /** @description Delete the user? */ remove: boolean = false ) { console.log('id', id, typeof id); } }
ヘルプ表示では、この説明がフラグまたは引数の後に表示されます:
$ ts-node app.ts test --help USAGE $ ts-node app.ts test ID ARGUMENTS ID The users identifier OPTIONS --remove Delete the user?