
2026/01/13 14:04
CLI の補完機能は、既に入力されたオプションを認識できるようになっているべきです。
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
改良された要約
Optique 0.10.0 は 型安全な依存関係システム を導入し、コマンドラインパーサが正確でコンテキストに応じたシェル補完と、Git ブランチやクラウド API などの実際のデータに対する検証を提供できるようにします。
追加機能
- 静的依存関係 (
) により、排他的なフラグセット(例:or()
、--json → --pretty
)を宣言できます。--csv → --delimiter - 実行時依存関係:
はソースオプションをマークします。dependency()
/derive()
はソースの値に依存するパーサを構築します。deriveAsync()
/deriveFrom()
は複数のオプション(例:deriveFromAsync()
+--env
)を結合して派生した選択肢を生成します。--region
パースフロー
- すべてのオプション宣言から依存関係を収集。
呼び出しで提供されたファクトリにより派生パーサを作成。derive*- これらのコンテキスト認識パーサで入力を再パースし、正しい検証と補完を実現。
Git 統合
同梱パッケージ
@optique/git は非同期パーサ(gitBranch、gitTag、gitRef)を提供し、isomorphic‑git を使用して Node.js と Deno の両方で Git リポジトリから読み取ります。これにより、CLI ツールは指定されたリポジトリパス(例:Git の -C オプション)に基づくブランチやタグの補完を提供できます。
利用可能性
Optique 0.10.0 のプレリリース (
0.10.0-dev.311) は次で入手可能です:
- npm:
npm install @optique/core@0.10.0-dev.311 - Deno:
deno add jsr:@optique/core@0.10.0-dev.311
今後の展望
将来のリリースでは、クラウドプロバイダー、データベース、コンテナレジストリなど他の外部システムへの依存関係処理を拡張し、安全で明確な CLI をさらに実現し、信頼性の高い補完と検証を提供できるようになる可能性があります。
このバージョンは、リストからすべての重要ポイントを明示的に含めつつ、明快かつ簡潔な主旨を保持しています。
本文
Git の
オプションを使ってみよう-C
git -C /path/to/repo checkout <TAB>
タブキーを押すと、現在のディレクトリではなく
/path/to/repo からブランチ名が補完されます。この補完はコンテキストに応じて動作します ― 他のオプションの値によって変わります。
ほとんどの CLI パーサはこうした依存関係を扱えません。各オプションを独立して処理するため、
--branch の補完が --repo の値を知ることができず、次のような二つの不満足な選択肢に陥ります。
- すべてのリポジトリからの全ブランチ候補を表示(無意味)
- 補完自体を完全に諦める
Optique 0.10.0 は、型安全性を保ったままこの問題を解決する依存関係システムを導入します。
静的依存関係:or()
or()Optique は
or() コンビネータである程度の依存オプションを扱えます:
import { flag, object, option, or, string } from "@optique/core"; const outputOptions = or( object({ json: flag("--json"), pretty: flag("--pretty"), }), object({ csv: flag("--csv"), delimiter: option("--delimiter", string()), }) );
TypeScript は
--json が true の場合は --pretty フィールドがあると知り、--csv が true の場合は --delimiter フィールドがあると知ります。パーサは実行時にこれを検証し、シェル補完も
--json が存在する時だけ --pretty を提案します。
定義時に有効な組み合わせが分かるケースではうまく動作しますが、ランタイム入力に依存するケース(リポジトリごとに変わるブランチ名など)には対応できません。
ランタイム依存関係
よくあるシナリオは次のようなものです:
が利用可能サービスを決定するデプロイ CLI--environment
がテーブル候補を決める DB ツール--connection
が表示されるリソースを制御するクラウド CLI--project
これらでは、依存オプションにユーザーが入力した値を知るまで有効な値は分かりません。Optique 0.10.0 は
dependency() と derive() でこのケースを扱います。
依存関係システム
概念は簡単です:あるオプションを 依存元 としてマークし、その値を使って派生パーサを作ります。
import { choice, dependency, message, object, option, string, } from "@optique/core"; function getRefsFromRepo(repoPath: string): string[] { // 実際には Git リポジトリから読み取る return ["main", "develop", "feature/login"]; } // 依存元としてマーク const repoParser = dependency(string()); // 派生パーサを作成 const refParser = repoParser.derive({ metavar: "REF", factory: (repoPath) => { const refs = getRefsFromRepo(repoPath); return choice(refs); }, defaultValue: () => ".", }); const parser = object({ repo: option("--repo", repoParser, { description: message`Path to the repository`, }), ref: option("--ref", refParser, { description: message`Git reference`, }), });
factory が依存関係を解決する場所です。ユーザーが
--repo に実際に入力した値を受け取り、そのリポジトリ固有の参照で検証できるパーサを返します。
内部構造:Optique は三段階解析戦略を採用しています。
- まずすべてのオプションを一度に解析し、依存値を収集
- 集めた値で
を呼び出し、具体的なパーサを生成factory - 派生オプションを再度解析して動的に作られたパーサで処理
これにより、検証と補完の両方が正しく機能します。すでに
--repo /some/path を入力済みなら、--ref の補完はそのパスから取得した参照を表示します。
@optique/git
でリポジトリ認識型補完
@optique/git@optique/git パッケージは Git リポジトリから非同期に値を読み取るパーサを提供します。依存関係システムと組み合わせれば、リポジトリ固有の補完を持つ CLI を簡単に構築できます。
import { command, dependency, message, object, option, string, } from "@optique/core"; import { gitBranch } from "@optique/git"; const repoParser = dependency(string()); const branchParser = repoParser.deriveAsync({ metavar: "BRANCH", factory: (repoPath) => gitBranch({ dir: repoPath }), defaultValue: () => ".", }); const checkout = command( "checkout", object({ repo: option("--repo", repoParser, { description: message`Path to the repository`, }), branch: option("--branch", branchParser, { description: message`Branch to checkout`, }), }) );
これで
my-cli checkout --repo /path/to/project --branch <TAB> と入力すると、補完は /path/to/project のブランチを表示します。defaultValue が "." に設定されているので、--repo が指定されなければ現在のディレクトリが使われます。
複数依存関係
派生パーサが複数オプションから値を取得する必要がある場合は
deriveFrom() を利用します:
import { choice, dependency, deriveFrom, message, object, option, } from "@optique/core"; function getAvailableServices(env: string, region: string): string[] { return [`${env}-api-${region}`, `${env}-web-${region}`]; } const envParser = dependency(choice(["dev", "staging", "prod"] as const)); const regionParser = dependency(choice(["us-east", "eu-west"] as const)); const serviceParser = deriveFrom({ dependencies: [envParser, regionParser] as const, metavar: "SERVICE", factory: (env, region) => { const services = getAvailableServices(env, region); return choice(services); }, defaultValues: () => ["dev", "us-east"] as const, }); const parser = object({ env: option("--env", envParser, { description: message`Deployment environment`, }), region: option("--region", regionParser, { description: message`Cloud region`, }), service: option("--service", serviceParser, { description: message`Service to deploy`, }), });
factory は依存配列と同じ順序で値を受け取り、いずれかが未指定の場合は defaultValues が使用されます。
非同期サポート
実際の依存解決では I/O(Git 読み込み、API 呼び出し、データベースアクセス)が必要になることがあります。
Optique は非同期バージョンを用意しています:
import { dependency, string } from "@optique/core"; import { gitBranch } from "@optique/git"; const repoParser = dependency(string()); const branchParser = repoParser.deriveAsync({ metavar: "BRANCH", factory: (repoPath) => gitBranch({ dir: repoPath }), defaultValue: () => ".", });
@optique/git は isomorphic‑git を内部で使用しているため、Node.js と Deno 両方で gitBranch(), gitTag(), gitRef() が動作します。同期的に処理したい場合は
deriveSync()、複数非同期依存を扱う場合は deriveFromAsync() を使用できます。
まとめ
依存関係システムを使えば、オプション同士が互いの値を認識し、検証だけでなくシェル補完も正しく機能する CLI が構築できます。
型安全性は TypeScript によって保証されるため、無効な組み合わせはコンパイル時に検出されます。
Git リポジトリやクラウドプロバイダ、データベース、コンテナレジストリなど、実行時まで有効値が分からない外部システムと対話するツールで特に有用です。
ユーザーが既に入力した情報を元に補完候補を動的に生成できるため、より直感的な UX を提供できます。
利用方法
この機能は Optique 0.10.0 で利用可能です。
プリリリース版の試用
deno add jsr:@optique/core@0.10.0-dev.311
または npm:
npm install @optique/core@0.10.0-dev.311
詳細は公式ドキュメントをご覧ください。