🐢
parseArgs を使って Node.js スクリプトのコマンド引数・オプションをいい感じに取得する
ことの発端
marked をつかって、 .md から .tsx ファイルをつくる簡単なNode.jsスクリプトを書いていました。
しかし、ハードコーディングしているパスの部分やコンポーネント名を動的に変えたいなと思い、CLIからオプションを渡せるように実装を変えようとしていました。
すごく簡単に実装するなら process.argv.slice(2) する、ライブラリを使うなら Commandar.js や yargs というものがあります。
選定している中で、 node:util に parseArgs というものが実装されていることを知ったため、今回はそれを利用してみることにしました。
parseArgs について
parseArgs は、 Node.js v20.0.0からstableになったものです。
例えば、コマンドオプションと引数を設定できるようにしたい場合に、
$ node ./foo.js bar.md path/to/dir --name TestComponent
次のようなコードを書くことで、コマンド引数やオプションを適切に取得できます。
const { parseArgs } = require('node:util')
const { values, positions } = parseArgs({
  args: process.args,
  allowPositionals: true, // コマンド引数を取得できるようにする設定
  options: {
    name: {
      type: 'string'
    }
  }
})
console.log({ values, positions })
実行結果は次のようになります。
$ node ./foo.js bar.md path/to/dir --name TestComponent
{
  values: [Object: null prototype] { name: 'TestComponent' },
  positionals: [ 'bar.md', 'path/to/dir' ]
}
values に、 options で設定したものがobjectで格納され、 positionals には未設定のものがはいるようなイメージです。
詳細は parseArgsのconfig部分をご参考ください。
これをベースにし、スクリプトを次のように書いてみました。
// foo.js
const { parseArgs } = require('node:util');
const fs = require('node:fs');
const { marked } = require('marked');
const { values } = parseArgs({
  args: process.args,
  options: {
    name: {
      type: 'string',
      short: 'n', // `-n` でも取得できるようにする設定
    },
    input: {
      type: 'string',
      short: 'i',
    },
    output: {
      type: 'string',
      short: 'o',
    },
  },
});
const markdown = fs.readFileSync(values.input, 'utf-8');
const html = marked(markdown);
const component = `
// NOTE: This component is generated by the script: foo.js.
export const ${values.name} = () => {
  return (
    <>${html}</>
  );
};
`;
fs.writeFileSync(values.output, component);
オプションには次を設定できるようにしています。
- 
--name(-n): コンポーネント名 - 
--input(-i): マークダウンのパス - 
--output(-o): 出力するコンポーネントファイルのパス 
今回の場合は引数を利用しなかったので、 allowPositionals は設定していません(デフォルトで false になっています)。
Node.js v20.0.0以上でとくにライブラリを使わずともいい感じに取得できるので、今後小さなスクリプトを書くときは積極的に利用していきたいです。
Discussion