REPL#

安定性: 2 - 安定

ソースコード: lib/repl.js

node:repl モジュールは、スタンドアロンプログラムとしても、他のアプリケーションに組み込むこともできるRead-Eval-Print-Loop(REPL)の実装を提供します。以下を使用してアクセスできます。

const repl = require('node:repl'); 

設計と機能#

node:replモジュールは、repl.REPLServerクラスをエクスポートします。repl.REPLServerのインスタンスは、実行中にユーザー入力の個々の行を受け入れ、ユーザー定義の評価関数に従ってそれらを評価し、結果を出力します。入力と出力は、それぞれstdinstdoutから、または任意のNode.js ストリームに接続できます。

repl.REPLServerのインスタンスは、入力の自動補完、補完プレビュー、単純なEmacsスタイルの行編集、複数行入力、ZSHのようなリバースiサーチ、ZSHのような部分文字列ベースの履歴検索、ANSIスタイルの出力、現在のREPLセッション状態の保存と復元、エラーリカバリ、およびカスタマイズ可能な評価関数をサポートしています。ANSIスタイルとEmacsスタイルの行編集をサポートしていない端末は、自動的に機能の制限されたセットにフォールバックします。

コマンドと特殊キー#

次の特殊コマンドは、すべてのREPLインスタンスでサポートされています。

  • .break: 複数行の式を入力しているときに、.breakコマンドを入力(またはCtrl+Cを押す)して、その式の追加入力または処理を中止します。
  • .clear: REPLのcontextを空のオブジェクトにリセットし、入力中の複数行の式をクリアします。
  • .exit: I/Oストリームを閉じ、REPLを終了させます。
  • .help: この特殊コマンドのリストを表示します。
  • .save: 現在のREPLセッションをファイルに保存します: > .save ./file/to/save.js
  • .load: ファイルを現在のREPLセッションにロードします。> .load ./file/to/load.js
  • .editor: エディターモードに入ります(Ctrl+Dで終了、Ctrl+Cでキャンセル)。
> .editor
// Entering editor mode (^D to finish, ^C to cancel)
function welcome(name) {
  return `Hello ${name}!`;
}

welcome('Node.js User');

// ^D
'Hello Node.js User!'
> 

REPLの次のキーの組み合わせには、これらの特殊な効果があります。

  • Ctrl+C: 1回押すと、.breakコマンドと同じ効果があります。空白行で2回押すと、.exitコマンドと同じ効果があります。
  • Ctrl+D: .exitコマンドと同じ効果があります。
  • Tab: 空白行で押すと、グローバルおよびローカル(スコープ)変数が表示されます。他の入力を入力中に押すと、関連する自動補完オプションが表示されます。

リバースiサーチに関連するキーバインドについては、reverse-i-searchを参照してください。その他のすべてのキーバインドについては、TTYキーバインドを参照してください。

デフォルト評価#

デフォルトでは、repl.REPLServerのすべてのインスタンスは、JavaScript式を評価し、Node.js組み込みモジュールへのアクセスを提供する評価関数を使用します。このデフォルトの動作は、repl.REPLServerインスタンスが作成されたときに、代替の評価関数を渡すことによってオーバーライドできます。

JavaScript式#

デフォルトのエバリュエータは、JavaScript式の直接評価をサポートしています。

> 1 + 1
2
> const m = 2
undefined
> m + 1
3 

ブロックまたは関数内でスコープが設定されていない限り、暗黙的またはconstlet、またはvarキーワードを使用して宣言された変数は、グローバルスコープで宣言されます。

グローバルスコープとローカルスコープ#

デフォルトのエバリュエータは、グローバルスコープに存在するすべての変数へのアクセスを提供します。各REPLServerに関連付けられたcontextオブジェクトに明示的に割り当てることにより、変数をREPLに公開できます。

const repl = require('node:repl');
const msg = 'message';

repl.start('> ').context.m = msg; 

contextオブジェクトのプロパティは、REPL内でローカルとして表示されます。

$ node repl_test.js
> m
'message' 

コンテキストプロパティは、デフォルトでは読み取り専用ではありません。読み取り専用のグローバルを指定するには、Object.defineProperty()を使用してコンテキストプロパティを定義する必要があります。

const repl = require('node:repl');
const msg = 'message';

const r = repl.start('> ');
Object.defineProperty(r.context, 'm', {
  configurable: false,
  enumerable: true,
  value: msg,
}); 
Node.jsコアモジュールへのアクセス#

デフォルトのエバリュエータは、使用時にNode.jsコアモジュールを自動的にREPL環境にロードします。たとえば、グローバル変数またはスコープ変数として宣言されていない場合、入力fsは、オンデマンドでglobal.fs = require('node:fs')として評価されます。

> fs.createReadStream('./some/file'); 
グローバルなキャッチされない例外#

REPLは、domainモジュールを使用して、そのREPLセッションのすべてのキャッチされない例外をキャッチします。

REPLでのこのdomainモジュールの使用には、次の副作用があります。

_(アンダースコア)変数の割り当て#

デフォルトのエバリュエータは、デフォルトで、最近評価された式の結果を特殊変数_(アンダースコア)に割り当てます。_に値を明示的に設定すると、この動作は無効になります。

> [ 'a', 'b', 'c' ]
[ 'a', 'b', 'c' ]
> _.length
3
> _ += 1
Expression assignment to _ now disabled.
4
> 1 + 1
2
> _
4 

同様に、_errorは、エラーがあった場合に最後に確認されたエラーを参照します。_errorに値を明示的に設定すると、この動作は無効になります。

> throw new Error('foo');
Uncaught Error: foo
> _error.message
'foo' 
awaitキーワード#

トップレベルでawaitキーワードのサポートが有効になっています。

> await Promise.resolve(123)
123
> await Promise.reject(new Error('REPL await'))
Uncaught Error: REPL await
    at REPL2:1:54
> const timeout = util.promisify(setTimeout);
undefined
> const old = Date.now(); await timeout(1000); console.log(Date.now() - old);
1002
undefined 

REPLでawaitキーワードを使用することの既知の制限の1つは、constキーワードとletキーワードのレキシカルスコープが無効になることです。

例:

> const m = await Promise.resolve(123)
undefined
> m
123
> const m = await Promise.resolve(234)
undefined
> m
234 

--no-experimental-repl-awaitは、REPLでのトップレベルのawaitを無効にする必要があります。

リバースiサーチ#

REPLは、ZSHと同様の双方向リバースiサーチをサポートしています。これは、Ctrl+Rで後方検索、Ctrl+Sで前方検索がトリガーされます。

重複した履歴エントリはスキップされます。

リバースサーチに対応しないキーが押されるとすぐに、エントリが受け入れられます。EscまたはCtrl+Cを押すと、キャンセルできます。

方向を変更すると、現在の位置から予測される方向の次のエントリがすぐに検索されます。

カスタム評価関数#

新しいrepl.REPLServerが作成される際、カスタム評価関数を提供できます。これは、例えば、完全にカスタマイズされたREPLアプリケーションを実装するために使用できます。

以下は、ある言語から別の言語へのテキスト翻訳を実行するREPLの仮想的な例を示しています。

const repl = require('node:repl');
const { Translator } = require('translator');

const myTranslator = new Translator('en', 'fr');

function myEval(cmd, context, filename, callback) {
  callback(null, myTranslator.translate(cmd));
}

repl.start({ prompt: '> ', eval: myEval }); 
回復可能なエラー#

REPLプロンプトで、Enterキーを押すと、現在の入力行がeval関数に送信されます。複数行の入力をサポートするために、eval関数は、提供されたコールバック関数にrepl.Recoverableのインスタンスを返すことができます。

function myEval(cmd, context, filename, callback) {
  let result;
  try {
    result = vm.runInThisContext(cmd);
  } catch (e) {
    if (isRecoverableError(e)) {
      return callback(new repl.Recoverable(e));
    }
  }
  callback(null, result);
}

function isRecoverableError(error) {
  if (error.name === 'SyntaxError') {
    return /^(Unexpected end of input|Unexpected token)/.test(error.message);
  }
  return false;
} 

REPL出力のカスタマイズ#

デフォルトでは、repl.REPLServerインスタンスは、提供されたWritableストリーム(デフォルトではprocess.stdout)に出力を書き込む前に、util.inspect()メソッドを使用して出力をフォーマットします。showProxy検査オプションはデフォルトでtrueに設定されており、colorsオプションはREPLのuseColorsオプションに応じてtrueに設定されています。

useColorsブールオプションは、構築時に指定して、デフォルトのライターがutil.inspect()メソッドからの出力を色付けするためにANSIスタイルコードを使用するように指示できます。

REPLがスタンドアロンプログラムとして実行されている場合は、REPL内部から検査のデフォルトを変更することもできます。それには、util.inspect()defaultOptionsをミラーリングするinspect.replDefaultsプロパティを使用します。

> util.inspect.replDefaults.compact = false;
false
> [1]
[
  1
]
> 

repl.REPLServerインスタンスの出力を完全にカスタマイズするには、構築時にwriterオプションに新しい関数を渡します。たとえば、次の例では、入力されたテキストを単純に大文字に変換します。

const repl = require('node:repl');

const r = repl.start({ prompt: '> ', eval: myEval, writer: myWriter });

function myEval(cmd, context, filename, callback) {
  callback(null, cmd);
}

function myWriter(output) {
  return output.toUpperCase();
} 

クラス:REPLServer#

repl.REPLServerのインスタンスは、repl.start()メソッドを使用するか、JavaScriptのnewキーワードを直接使用して作成されます。

const repl = require('node:repl');

const options = { useColors: true };

const firstInstance = repl.start(options);
const secondInstance = new repl.REPLServer(options); 

イベント:'exit'#

'exit'イベントは、REPLが、入力として.exitコマンドを受信した場合、ユーザーがCtrl+Cを2回押してSIGINTを通知した場合、または入力ストリームでCtrl+Dを押して'end'を通知した場合のいずれかで終了したときに発行されます。リスナーコールバックは引数なしで呼び出されます。

replServer.on('exit', () => {
  console.log('Received "exit" event from repl!');
  process.exit();
}); 

イベント:'reset'#

'reset'イベントは、REPLのコンテキストがリセットされるときに発行されます。これは、REPLがデフォルトの評価機能を使用しておらず、repl.REPLServerインスタンスがuseGlobalオプションをtrueに設定して作成された場合を除き.clearコマンドが入力として受信されるたびに発生します。リスナーコールバックは、唯一の引数としてcontextオブジェクトへの参照とともに呼び出されます。

これは主に、REPLコンテキストを事前定義された状態に再初期化するために使用できます。

const repl = require('node:repl');

function initializeContext(context) {
  context.m = 'test';
}

const r = repl.start({ prompt: '> ' });
initializeContext(r.context);

r.on('reset', initializeContext); 

このコードが実行されると、グローバルな'm'変数を変更できますが、.clearコマンドを使用して初期値にリセットできます。

$ ./node example.js
> m
'test'
> m = 1
1
> m
1
> .clear
Clearing context...
> m
'test'
> 

replServer.defineCommand(keyword, cmd)#

replServer.defineCommand()メソッドは、新しい.プレフィックス付きコマンドをREPLインスタンスに追加するために使用されます。このようなコマンドは、.に続いてkeywordを入力することで呼び出されます。cmdは、Functionまたは次のプロパティを持つObjectのいずれかです。

  • help <文字列> .helpが入力されたときに表示されるヘルプテキスト(オプション)。
  • action <関数> 実行する関数。必要に応じて単一の文字列引数を受け入れます。

次の例は、REPLインスタンスに追加された2つの新しいコマンドを示しています。

const repl = require('node:repl');

const replServer = repl.start({ prompt: '> ' });
replServer.defineCommand('sayhello', {
  help: 'Say hello',
  action(name) {
    this.clearBufferedCommand();
    console.log(`Hello, ${name}!`);
    this.displayPrompt();
  },
});
replServer.defineCommand('saybye', function saybye() {
  console.log('Goodbye!');
  this.close();
}); 

新しいコマンドは、REPLインスタンス内から使用できます。

> .sayhello Node.js User
Hello, Node.js User!
> .saybye
Goodbye! 

replServer.displayPrompt([preserveCursor])#

replServer.displayPrompt()メソッドは、ユーザーからの入力を受け入れるようにREPLインスタンスを準備し、構成されたpromptoutputの新しい行に出力し、新しい入力を受け入れるようにinputを再開します。

複数行の入力が入力されている場合、「プロンプト」ではなく省略記号が出力されます。

preserveCursortrueの場合、カーソルの配置は0にリセットされません。

replServer.displayPromptメソッドは、主にreplServer.defineCommand()メソッドを使用して登録されたコマンドのアクション関数内から呼び出すことを目的としています。

replServer.clearBufferedCommand()#

replServer.clearBufferedCommand()メソッドは、バッファリングされているがまだ実行されていないコマンドをクリアします。このメソッドは、主にreplServer.defineCommand()メソッドを使用して登録されたコマンドのアクション関数内から呼び出すことを目的としています。

replServer.parseREPLKeyword(keyword[, rest])#

安定度:0 - 非推奨。

  • keyword <文字列> 解析および実行する可能性のあるキーワード
  • rest <任意> キーワードコマンドへのパラメーター
  • 戻り値:<ブール値>

REPLServerキーワードを解析および実行するために使用される内部メソッド。keywordが有効なキーワードの場合はtrueを返し、それ以外の場合はfalseを返します。

replServer.setupHistory(historyPath, callback)#

REPLインスタンスの履歴ログファイルを初期化します。Node.jsバイナリを実行し、コマンドラインREPLを使用する場合、履歴ファイルはデフォルトで初期化されます。ただし、プログラムでREPLを作成する場合はそうではありません。REPLインスタンスをプログラムで操作する場合は、このメソッドを使用して履歴ログファイルを初期化します。

repl.builtinModules#

すべてのNode.jsモジュールの名前のリスト(例:'http')。

repl.start([options])#

  • options <オブジェクト> | <文字列>
    • prompt <文字列> 表示する入力プロンプト。デフォルト:'> '(末尾にスペース)。
    • input <stream.Readable> REPL入力が読み込まれるReadableストリーム。デフォルト:process.stdin
    • output <stream.Writable> REPL出力が書き込まれるWritableストリーム。デフォルト:process.stdout
    • terminal <ブール値> trueの場合、outputがTTYターミナルとして扱われることを指定します。デフォルト:インスタンス化時にoutputストリームのisTTYプロパティの値を確認します。
    • eval <関数> 入力された各行を評価するときに使用する関数。デフォルト:JavaScriptのeval()関数の非同期ラッパー。eval関数は、入力が不完全であり、追加の行を求めるプロンプトを表示することを示すために、repl.Recoverableでエラーになる場合があります。
    • useColors <ブール値> trueの場合、デフォルトのwriter関数に、REPL出力にANSIカラー スタイルを含める必要があることを指定します。カスタムのwriter関数が提供されている場合、これは効果がありません。デフォルト:REPLインスタンスのterminalの値がtrueの場合、outputストリームでのカラーサポートを確認します。
    • useGlobal <ブール値> trueの場合、デフォルトの評価関数が、REPLインスタンス用に新しい個別のコンテキストを作成するのではなく、コンテキストとしてJavaScriptのglobalを使用することを指定します。node CLI REPLは、この値をtrueに設定します。デフォルト:false
    • ignoreUndefined <ブール値> trueの場合、デフォルトのライターが、コマンドの戻り値がundefinedと評価される場合、その値を書き込まないように指定します。デフォルト:false
    • writer <関数> 各コマンドの出力をフォーマットしてからoutputに書き込むために呼び出す関数。デフォルト:util.inspect()
    • completer <関数> カスタムのTabオートコンプリートに使用されるオプションの関数。例については、readline.InterfaceCompleterを参照してください。
    • replMode <シンボル> デフォルトの評価機能が、すべてのJavaScriptコマンドを厳密モードで実行するか、デフォルト(スロッピー)モードで実行するかを指定するフラグ。受け入れられる値は次のとおりです。
      • repl.REPL_MODE_SLOPPY は、式をスロッピーモードで評価します。
      • repl.REPL_MODE_STRICT は、式を厳格モードで評価します。これは、すべての REPL ステートメントの先頭に 'use strict' を付加することと同等です。
    • breakEvalOnSigint <boolean> Ctrl+C が押されたときなど、SIGINT を受信したときに現在のコードの評価を停止します。これは、カスタムの eval 関数と組み合わせて使用することはできません。デフォルト: false
    • preview <boolean> REPL がオートコンプリートと出力プレビューを表示するかどうかを定義します。デフォルト: デフォルトの eval 関数を使用する場合は true で、カスタムの eval 関数を使用する場合は false です。terminal が falsy の場合、プレビューは表示されず、preview の値は効果がありません。
  • 戻り値: <repl.REPLServer>

repl.start() メソッドは、repl.REPLServer インスタンスを作成して起動します。

options が文字列の場合、入力プロンプトを指定します。

const repl = require('node:repl');

// a Unix style prompt
repl.start('$ '); 

Node.js REPL#

Node.js 自体は、JavaScript を実行するための独自のインタラクティブインターフェースを提供するために、node:repl モジュールを使用しています。これは、引数を渡さずに Node.js バイナリを実行する(または -i 引数を渡す)ことで使用できます。

$ node
> const a = [1, 2, 3];
undefined
> a
[ 1, 2, 3 ]
> a.forEach((v) => {
...   console.log(v);
...   });
1
2
3 

環境変数オプション#

Node.js REPL のさまざまな動作は、次の環境変数を使用してカスタマイズできます。

  • NODE_REPL_HISTORY: 有効なパスが指定された場合、永続的な REPL 履歴は、ユーザーのホームディレクトリにある .node_repl_history ではなく、指定されたファイルに保存されます。この値を '' (空文字列) に設定すると、永続的な REPL 履歴が無効になります。値から空白がトリミングされます。Windows プラットフォームでは、空の値を持つ環境変数は無効であるため、永続的な REPL 履歴を無効にするには、この変数を 1 つ以上のスペースに設定します。
  • NODE_REPL_HISTORY_SIZE: 履歴が利用可能な場合に、保持される履歴の行数を制御します。正の数である必要があります。デフォルト: 1000
  • NODE_REPL_MODE: 'sloppy' または 'strict' のいずれかです。デフォルト: 'sloppy' で、非厳格モードのコードを実行できます。

永続的な履歴#

デフォルトでは、Node.js REPL は、ユーザーのホームディレクトリにある .node_repl_history ファイルに入力を保存することにより、node REPL セッション間で履歴を永続化します。これは、環境変数 NODE_REPL_HISTORY='' を設定することで無効にできます。

高度なラインエディタで Node.js REPL を使用する#

高度なラインエディタの場合は、環境変数 NODE_NO_READLINE=1 を設定して Node.js を起動します。これにより、メインとデバッガ REPL が標準端末設定で起動し、rlwrap での使用が可能になります。

たとえば、次のものを .bashrc ファイルに追加できます。

alias node="env NODE_NO_READLINE=1 rlwrap node" 

単一の実行インスタンスに対して複数の REPL インスタンスを起動する#

単一の global オブジェクトを共有するが、別々の I/O インターフェースを持つ Node.js の単一の実行インスタンスに対して、複数の REPL インスタンスを作成および実行できます。

たとえば、次の例では、stdin、Unix ソケット、および TCP ソケットに別々の REPL を提供します。

const net = require('node:net');
const repl = require('node:repl');
let connections = 0;

repl.start({
  prompt: 'Node.js via stdin> ',
  input: process.stdin,
  output: process.stdout,
});

net.createServer((socket) => {
  connections += 1;
  repl.start({
    prompt: 'Node.js via Unix socket> ',
    input: socket,
    output: socket,
  }).on('exit', () => {
    socket.end();
  });
}).listen('/tmp/node-repl-sock');

net.createServer((socket) => {
  connections += 1;
  repl.start({
    prompt: 'Node.js via TCP socket> ',
    input: socket,
    output: socket,
  }).on('exit', () => {
    socket.end();
  });
}).listen(5001); 

コマンドラインからこのアプリケーションを実行すると、stdin で REPL が起動します。他の REPL クライアントは、Unix ソケットまたは TCP ソケット経由で接続できます。たとえば、telnet は TCP ソケットへの接続に役立ち、socat は Unix ソケットと TCP ソケットの両方に接続するために使用できます。

stdin の代わりに Unix ソケットベースのサーバーから REPL を起動することにより、再起動せずに長期間実行されている Node.js プロセスに接続できます。

net.Server および net.Socket インスタンス上で "フル機能" (terminal) の REPL を実行する例については、https://gist.github.com/TooTallNate/2209310 を参照してください。

curl(1) を介して REPL インスタンスを実行する例については、https://gist.github.com/TooTallNate/2053342 を参照してください。