以下の内容はhttps://blog.inorinrinrin.com/entry/2025/12/12/205344より取得しました。


Hono CLIのコードを読んでるうちにCommander.js向けのESLint Pluginを自作してた件

Commander.jsはJS/TS向けのCLI作成キットだ。

github.com

こういう感じでCLIに必要な要素をガリガリと定義していける。

const { program } = require('commander');

program
  .option('--first')
  .option('-s, --separator <char>')
  .argument('<string>');

program.parse();

const options = program.opts();
const limit = options.first ? 1 : undefined;
console.log(program.args[0].split(options.separator, limit));

なんでCommander.jsに目がいったのか?

最近Hono CLIをずっと見ているから。

github.com

Hono CLIはその名の通りHonoのCLIで、内部的にはCommander.jsをガッツリ活用している。例えばhono requestコマンドだとこんな感じ。

export function requestCommand(program: Command) {
  program
    .command('request')
    .description('Send request to Hono app using app.request()')
    .argument('[file]', 'Path to the Hono app file')
    .option('-P, --path <path>', 'Request path', '/')
    .option('-X, --method <method>', 'HTTP method', 'GET')
    .option('-d, --data <data>', 'Request body data')
    .option('-w, --watch', 'Watch for changes and resend request', false)
    .option('-e, --exclude', 'Exclude protocol response headers in the output', false)
    .option(
      '-H, --header <header>',
      'Custom headers',
      (value: string, previous: string[]) => {
        return previous ? [...previous, value] : [value]
      },
      [] as string[]
    )
    .action(async (file: string | undefined, options: RequestOptions) => {
       // 以下略

なんでESLintのことを思い出したのか?

最近 ESLintとPrettierのコードリーディングでASTベースの静的解析を理解する | TypeScriptでCLIを作って学ぶAST | Think IT(シンクイット) という素晴らしい記事を拝読してみた結果、理解を深めるついでに自分でもESLintの何か作ってみたくなったから。

だいたいこのへんがわかると、なんとなーくESLintがどうやって解析してるのかを理解できる。

あとはHono CLIにコントリビュートする過程でyusukebeさんと会話するうちに、僕も「自分があると便利そ〜」「これよくない??」っていうものを作って公開してみたくなったから。

何をlintしたかったのか?

上記のコードのoptionメソッドが気になっていた。

optionメソッドの第一引数flagsのJSDoc上の型はstringとなっているので、自由に文字列を渡すことが理論上可能

短縮と正式の順序が逆になってても怒られない

最後は好みだけど、オプションはアルファベット順の方がわかりやすくない?

この方が整頓されてる感じがして個人的には好き

ってことで作ったのがこれ

https://www.npmjs.com/package/eslint-plugin-commander-option-flags

github.com

実装の簡単な説明はREADMEに書いてるのでそっちを参照されたし。

デモ

youtu.be

アルファベット順に並んでなかったりするとwarnで怒ってくれて、eslint --fixすると修正までしてくれる。

Getting Start

npm i eslint --save-dev

eslint.config.mjsに以下のように修正を入れる。

  {
    plugins: {
      'commander-option-flags': commanderOptionFlags,
    },
    rules: {
      'commander-option-flags/commander-option-flags': ['warn', { order: 'long' }],
    },
  },

{ order: 'long' }の部分で、アルファベットのソート基準を-pのほうか、--pathの方かを決められる。これは、-X, --method <HTTP Method>のように違うエイリアスが割り当てられる場合が考えられるから。

おわりに

Commander.jsで要領をつかめたので、次は自分が一番好きなCLIツールのcitty向けにもっとガッツリ作ってみようと思う。

2025/12/15 追記

citty向けのeslint-pluginも作成し、リリースしました。

github.com




以上の内容はhttps://blog.inorinrinrin.com/entry/2025/12/12/205344より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14