最近、Node.jsで標準入力を取得する方法を知ったので、CLIを作って遊んでいる

[ Node.js v10.16.3 ]

標準入力は readline で取得する。

ここではサンプルとして、FFのマジックポットを作る。マジックポットはエリクサーというアイテムを強請ってくるモンスターで、エリクサーを渡さないと攻撃してくる。エリクサーをあげれば去っていく。

ユーザーに自由に入力させる

ブラウザで言うところの prompt() のように、ユーザーに値を入力させてみる。

以下のコードをファイルに保存して node コマンドで実行する。

const readline = require('readline');

/**
 * メイン処理
 */
const main = async () => {
  for (;;) {
    const answer = await prompt('エリクサーちょうだい!');
    if (['あげる', 'はい', 'どうぞ'].includes(answer)) {
      console.log('ありがとう!^_^');
      break;
    }
    else if (['あげない', 'だめ', 'ダメ', '駄目'].includes(answer)) {
      console.log('死ね!');
    }
    console.log('');  // 改行
  }
};

/**
 * ユーザーに値を入力させる
 */
const prompt = async (msg) => {
  console.log(msg);
  const answer = await question('> ');
  return answer.trim();
};

/**
 * 標準入力を取得する
 */
const question = (question) => {
  const readlineInterface = readline.createInterface({
    input: process.stdin,
    output: process.stdout
  });
  return new Promise((resolve) => {
    readlineInterface.question(question, (answer) => {
      resolve(answer);
      readlineInterface.close();
    });
  });
};

// 起動
(async () => {
  await main();
})();

実行するとコンソールに以下のように表示され、ユーザーの入力が可能な状態となる。

エリクサーちょうだい!
>

何も入力せずにEnterキーを押しても、永遠に「エリクサーちょうだい!」と言われ続ける。

試しに「だめ」「あげない」などと入力してEnterキーを押すと、暴言を吐かれたうえ、また「エリクサーちょうだい!」に戻る。

エリクサーちょうだい!
> だめ
死ね!

エリクサーちょうだい!
>

仕方なく「あげる」「どうぞ」などと入力すれば、マジックポットはお礼を言って、プログラムは終了する。

エリクサーちょうだい!
> あげる
ありがとう!^_^

ユーザーにYes/Noで答えさせる

上のサンプルは、実際にはYes/Noで回答できる程度の質問だった。

ブラウザで言うところの confirm() みたいなものを作って、それを使うように変えてみる。

const readline = require('readline');

/**
 * メイン処理
 */
const main = async () => {
  for (;;) {
    console.log('エリクサーちょうだい!');
    if (await confirm('> あげますか?')) {
      console.log('ありがとう!^_^');
      break;
    } else {
      console.log('死ね!');
    }
    console.log('');  // 改行
  }
};

/**
 * ユーザーにYes/Noで答えられる質問をする
 */
const confirm = async (msg) => {
  const answer = await question(`${msg}(y/n): `);
  return answer.trim().toLowerCase() === 'y';
};

/**
 * 標準入力を取得する
 */
const question = (question) => {
  const readlineInterface = readline.createInterface({
    input: process.stdin,
    output: process.stdout
  });
  return new Promise((resolve) => {
    readlineInterface.question(question, (answer) => {
      resolve(answer);
      readlineInterface.close();
    });
  });
};

// 起動
(async () => {
  await main();
})();

実行するとコンソールに以下のように表示され、ユーザーに y か n の入力を促す。

エリクサーちょうだい!
> あげますか?(y/n):

ここでは何も入力しないとNo扱いにしているので、何も入力しなかろうが n を入力しようが、同様に暴言を吐かれる。

エリクサーちょうだい!
> あげますか?(y/n):
死ね!

エリクサーちょうだい!
> あげますか?(y/n): n
死ね!

エリクサーちょうだい!
> あげますか?(y/n):

y を入力すれば、マジックポットは満足して終了する。

エリクサーちょうだい!
> あげますか?(y/n): y
ありがとう!^_^

以上。