Skip to content

REPL

[Стабильно: 2 - Стабильно]

Стабильно: 2 Стабильность: 2 - Стабильно

Исходный код: lib/repl.js

Модуль node:repl предоставляет реализацию цикла «читать-выполнять-печатать-цикл» (REPL), доступную как в виде отдельной программы, так и для включения в другие приложения. Доступ к нему можно получить с помощью:

js
import repl from 'node:repl'
js
const repl = require('node:repl')

Дизайн и особенности

Модуль node:repl экспортирует класс repl.REPLServer. Во время работы экземпляры repl.REPLServer принимают отдельные строки пользовательского ввода, оценивают их в соответствии с определяемой пользователем функцией оценки, а затем выводят результат. Ввод и вывод могут осуществляться соответственно из stdin и stdout или могут быть подключены к любому потоку Node.js stream.

Экземпляры repl.REPLServer поддерживают автоматическое завершение ввода, предварительный просмотр завершения, упрощенное редактирование строк в стиле Emacs, многострочный ввод, обратный поиск по истории в стиле ZSH, поиск по истории на основе подстрок в стиле ZSH, вывод в стиле ANSI, сохранение и восстановление текущего состояния сессии REPL, восстановление после ошибок и настраиваемые функции оценки. Терминалы, которые не поддерживают стили ANSI и редактирование строк в стиле Emacs, автоматически переходят на ограниченный набор функций.

Команды и специальные клавиши

Все экземпляры REPL поддерживают следующие специальные команды:

  • .break: При вводе многострочного выражения введите команду .break (или нажмите Ctrl+C), чтобы прервать дальнейший ввод или обработку этого выражения.
  • .clear: Сбрасывает контекст REPL context до пустого объекта и очищает любой вводимый многострочный оператор.
  • .exit: Закрывает поток ввода-вывода, вызывая выход из REPL.
  • .help: Показывает этот список специальных команд.
  • .save: Сохраняет текущую сессию REPL в файл: \> .save ./file/to/save.js
  • .load: Загружает файл в текущую сессию REPL. \> .load ./file/to/load.js
  • .editor: Входит в режим редактора (+ для завершения, Ctrl+C для отмены).
bash
> .editor
// Вход в режим редактора (^D для завершения, ^C для отмены)
function welcome(name) {
  return `Hello ${name}!`;
}

welcome('Node.js User');

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

Следующие сочетания клавиш в REPL имеют следующие специальные эффекты:

  • Ctrl+C: При однократном нажатии имеет тот же эффект, что и команда .break. При двукратном нажатии на пустой строке имеет тот же эффект, что и команда .exit.
  • Ctrl+D: Имеет тот же эффект, что и команда .exit.
  • Tab: При нажатии на пустой строке отображает глобальные и локальные (область видимости) переменные. При нажатии во время ввода другого ввода отображает соответствующие варианты автозавершения.

Для сочетаний клавиш, связанных с обратным поиском по истории, см. reverse-i-search. Для всех остальных сочетаний клавиш см. сочетания клавиш TTY.

Вычисление по умолчанию

По умолчанию все экземпляры repl.REPLServer используют функцию вычисления, которая вычисляет выражения JavaScript и предоставляет доступ к встроенным модулям Node.js. Это поведение по умолчанию может быть переопределено путем передачи альтернативной функции вычисления при создании экземпляра repl.REPLServer.

Выражения JavaScript

Оценщик по умолчанию поддерживает прямое вычисление выражений JavaScript:

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

Если не указано иное в блоках или функциях, переменные, объявленные неявно или с помощью ключевых слов const, let или var, объявляются в глобальной области видимости.

Глобальная и локальная область видимости

Оценщик по умолчанию предоставляет доступ ко всем переменным, существующим в глобальной области видимости. Можно явно предоставить переменную REPL, присвоив её объекту context, связанному с каждым REPLServer:

js
import repl from 'node:repl'
const msg = 'message'

repl.start('> ').context.m = msg
js
const repl = require('node:repl')
const msg = 'message'

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

Свойства объекта context отображаются как локальные внутри REPL:

bash
$ node repl_test.js
> m
'message'

Свойства контекста по умолчанию не являются доступными только для чтения. Для указания глобальных переменных, доступных только для чтения, свойства контекста должны быть определены с помощью Object.defineProperty():

js
import repl from 'node:repl'
const msg = 'message'

const r = repl.start('> ')
Object.defineProperty(r.context, 'm', {
  configurable: false,
  enumerable: true,
  value: msg,
})
js
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').

bash
> fs.createReadStream('./some/file');

Глобальные неперехваченные исключения

[История]

ВерсияИзменения
v12.3.0Событие 'uncaughtException' теперь срабатывает, если REPL используется как отдельная программа.

REPL использует модуль domain для перехвата всех неперехваченных исключений для данного сеанса REPL.

Использование модуля domain в REPL имеет следующие побочные эффекты:

Присваивание переменной _ (подчеркивание)

[История]

ВерсияИзменения
v9.8.0Добавлена поддержка _error.

По умолчанию интерпретатор по умолчанию присваивает результат последнего вычисленного выражения специальной переменной _ (подчеркивание). Явное присваивание значения _ отключает это поведение.

bash
> [ 'a', 'b', 'c' ]
[ 'a', 'b', 'c' ]
> _.length
3
> _ += 1
Присваивание выражения _ теперь отключено.
4
> 1 + 1
2
> _
4

Аналогично, _error будет ссылаться на последнюю обнаруженную ошибку, если таковая имелась. Явное присваивание значения _error отключает это поведение.

bash
> throw new Error('foo');
Неперехваченная ошибка: foo
> _error.message
'foo'

Ключевое слово await

Поддержка ключевого слова await включена на верхнем уровне.

bash
> await Promise.resolve(123)
123
> await Promise.reject(new Error('REPL await'))
Неперехваченная ошибка: REPL await
    в REPL2:1:54
> const timeout = util.promisify(setTimeout);
undefined
> const old = Date.now(); await timeout(1000); console.log(Date.now() - old);
1002
undefined

Одно известное ограничение использования ключевого слова await в REPL заключается в том, что оно делает недействительной лексическую область видимости ключевых слов const и let.

Например:

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

--no-experimental-repl-await отключает await верхнего уровня в REPL.

Добавлен в: v13.6.0, v12.17.0

REPL поддерживает двунаправленный обратный интерактивный поиск, аналогичный ZSH. Он активируется с помощью + для поиска назад и + для поиска вперёд.

Дубликаты записей истории будут пропущены.

Записи принимаются, как только нажата любая клавиша, не соответствующая обратному поиску. Отмена возможна нажатием или +.

Изменение направления немедленно запускает поиск следующей записи в ожидаемом направлении от текущей позиции.

Пользовательские функции оценки

При создании нового repl.REPLServer можно указать пользовательскую функцию оценки. Это может использоваться, например, для реализации полностью настраиваемых приложений REPL.

Ниже приведён пример REPL, который возводит заданное число в квадрат:

js
import repl from 'node:repl'

function byThePowerOfTwo(number) {
  return number * number
}

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

repl.start({ prompt: 'Enter a number: ', eval: myEval })
js
const repl = require('node:repl')

function byThePowerOfTwo(number) {
  return number * number
}

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

repl.start({ prompt: 'Enter a number: ', eval: myEval })

Восстанавливаемые ошибки

В командной строке REPL нажатие отправляет текущую строку ввода в функцию eval. Для поддержки многострочного ввода функция eval может возвращать экземпляр repl.Recoverable в предоставленную функцию обратного вызова:

js
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 форматируют вывод с помощью метода util.inspect() перед записью вывода в предоставленный поток Writable (process.stdout по умолчанию). Опция проверки showProxy установлена в значение true по умолчанию, а опция colors устанавливается в значение true в зависимости от опции useColors REPL.

Булеву опцию useColors можно указать при создании, чтобы указать стандартному записывающему устройству использовать коды стиля ANSI для раскрашивания вывода из метода util.inspect().

Если REPL запускается как отдельная программа, также можно изменить параметры проверки по умолчанию REPL изнутри REPL, используя свойство inspect.replDefaults, которое отражает defaultOptions из util.inspect().

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

Для полной настройки вывода экземпляра repl.REPLServer передайте новую функцию для опции writer при создании. Например, в следующем примере любой входной текст просто преобразуется в верхний регистр:

js
import repl from '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()
}
js
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

Добавлено в: v0.1.91

Экземпляры repl.REPLServer создаются с помощью метода repl.start() или напрямую с помощью JavaScript-ключавого слова new.

js
import repl from 'node:repl'

const options = { useColors: true }

const firstInstance = repl.start(options)
const secondInstance = new repl.REPLServer(options)
js
const repl = require('node:repl')

const options = { useColors: true }

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

Событие: 'exit'

Добавлено в: v0.7.7

Событие 'exit' генерируется при выходе из REPL, либо при получении команды .exit в качестве входных данных, либо при двойном нажатии пользователя + для сигнализации SIGINT, либо при нажатии + для сигнализации 'end' во входном потоке. Обратный вызов прослушивателя вызывается без аргументов.

js
replServer.on('exit', () => {
  console.log('Получено событие "exit" от repl!')
  process.exit()
})

Событие: 'reset'

Добавлено в: v0.11.0

Событие 'reset' генерируется при сбросе контекста REPL. Это происходит всякий раз, когда команда .clear поступает в качестве входных данных, если только REPL не использует стандартный интерпретатор и экземпляр repl.REPLServer не был создан с параметром useGlobal, установленным в значение true. Обратный вызов прослушивателя будет вызван со ссылкой на объект context в качестве единственного аргумента.

Это может использоваться в основном для повторной инициализации контекста REPL до некоторого предопределенного состояния:

js
import repl from 'node:repl'

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

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

r.on('reset', initializeContext)
js
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:

bash
$ ./node example.js
> m
'test'
> m = 1
1
> m
1
> .clear
Очистка контекста...
> m
'test'
>

replServer.defineCommand(keyword, cmd)

Добавлено в: v0.3.0

  • keyword <string> Ключевое слово команды (без ведущего символа .).
  • cmd <Object> | <Function> Функция, вызываемая при обработке команды.

Метод replServer.defineCommand() используется для добавления новых команд с префиксом . в экземпляр REPL. Такие команды вызываются путем ввода символа . с последующим указанием keyword. cmd представляет собой либо Function, либо Object со следующими свойствами:

  • help <string> Текст справки, который будет отображаться при вводе .help (необязательно).
  • action <Function> Функция для выполнения, необязательно принимающая один строковый аргумент.

В следующем примере показаны две новые команды, добавленные в экземпляр REPL:

js
import repl from 'node:repl'

const replServer = repl.start({ prompt: '> ' })
replServer.defineCommand('sayhello', {
  help: 'Поздороваться',
  action(name) {
    this.clearBufferedCommand()
    console.log(`Привет, ${name}!`)
    this.displayPrompt()
  },
})
replServer.defineCommand('saybye', function saybye() {
  console.log('До свидания!')
  this.close()
})
js
const repl = require('node:repl')

const replServer = repl.start({ prompt: '> ' })
replServer.defineCommand('sayhello', {
  help: 'Поздороваться',
  action(name) {
    this.clearBufferedCommand()
    console.log(`Привет, ${name}!`)
    this.displayPrompt()
  },
})
replServer.defineCommand('saybye', function saybye() {
  console.log('До свидания!')
  this.close()
})

Затем новые команды могут использоваться в экземпляре REPL:

bash
> .sayhello Node.js User
Привет, Node.js User!
> .saybye
До свидания!

replServer.displayPrompt([preserveCursor])

Добавлен в: v0.1.91

Метод replServer.displayPrompt() подготавливает экземпляр REPL для ввода от пользователя, выводя настроенный prompt на новую строку в output и возобновляя input для принятия нового ввода.

При вводе многострочного ввода вместо «prompt» выводится многоточие.

Когда preserveCursor имеет значение true, положение курсора не будет сброшено на 0.

Метод replServer.displayPrompt предназначен в первую очередь для вызова из функции действия для команд, зарегистрированных с помощью метода replServer.defineCommand().

replServer.clearBufferedCommand()

Добавлен в: v9.0.0

Метод replServer.clearBufferedCommand() очищает любую команду, которая была буферизована, но еще не выполнена. Этот метод предназначен в первую очередь для вызова из функции действия для команд, зарегистрированных с помощью метода replServer.defineCommand().

replServer.setupHistory(historyPath, callback)

Добавлен в: v11.10.0

  • historyPath <string> путь к файлу истории
  • callback <Function> вызывается, когда запись истории готова или при ошибке

Инициализирует файл журнала истории для экземпляра REPL. При выполнении двоичного файла Node.js и использовании REPL командной строки файл истории инициализируется по умолчанию. Однако это не так, когда REPL создается программным способом. Используйте этот метод для инициализации файла журнала истории при работе с экземплярами REPL программным способом.

repl.builtinModules

Добавлен в: v14.5.0

Список имен всех модулей Node.js, например, 'http'.

repl.start([options])

[История]

ВерсияИзменения
v13.4.0, v12.17.0Доступен параметр preview.
v12.0.0Параметр terminal теперь во всех случаях следует стандартному описанию, а useColors проверяет hasColors(), если доступно.
v10.0.0Режим REPL_MAGIC_MODE параметра replMode удалён.
v6.3.0Теперь поддерживается параметр breakEvalOnSigint.
v5.8.0Параметр options теперь необязателен.
v0.1.91Добавлено в: v0.1.91
  • options <Object> | <string>

    • prompt <string> Выводимая подсказка для ввода. По умолчанию: '\> ' (с завершающим пробелом).

    • input <stream.Readable> Поток Readable, из которого будет считываться ввод REPL. По умолчанию: process.stdin.

    • output <stream.Writable> Поток Writable, в который будет выводиться результат REPL. По умолчанию: process.stdout.

    • terminal <boolean> Если true, указывает, что output следует обрабатывать как терминал TTY. По умолчанию: проверка значения свойства isTTY в потоке output при создании экземпляра.

    • eval <Function> Функция, используемая для вычисления каждой введённой строки. По умолчанию: асинхронный обёртку для функции JavaScript eval(). Функция eval может выдавать ошибку repl.Recoverable, чтобы указать, что ввод был неполным, и запросить дополнительные строки.

    • useColors <boolean> Если true, указывает, что функция writer по умолчанию должна включать стилизацию ANSI-цветов в вывод REPL. Если предоставлена пользовательская функция writer, это не имеет эффекта. По умолчанию: проверка поддержки цвета в потоке output, если значение terminal экземпляра REPL равно true.

    • useGlobal <boolean> Если true, указывает, что функция вычисления по умолчанию будет использовать JavaScript global в качестве контекста, а не создавать новый отдельный контекст для экземпляра REPL. В REPL командной строки node это значение установлено в true. По умолчанию: false.

    • ignoreUndefined <boolean> Если true, указывает, что функция writer по умолчанию не будет выводить возвращаемое значение команды, если оно равно undefined. По умолчанию: false.

    • writer <Function> Функция, вызываемая для форматирования вывода каждой команды перед записью в output. По умолчанию: util.inspect().

    • completer <Function> Необязательная функция, используемая для пользовательского автодополнения Tab. См. readline.InterfaceCompleter для примера.

    • replMode <symbol> Флаг, указывающий, выполняет ли интерпретатор по умолчанию все команды JavaScript в строгом режиме или в режиме по умолчанию (нестрогом). Допустимые значения:

    • repl.REPL_MODE_SLOPPY для вычисления выражений в нестрогом режиме.

    • repl.REPL_MODE_STRICT для вычисления выражений в строгом режиме. Это эквивалентно добавлению 'use strict' перед каждым оператором repl.

    • breakEvalOnSigint <boolean> Прекратить вычисление текущего фрагмента кода при получении SIGINT, например, когда нажата клавиша + . Это нельзя использовать вместе с пользовательской функцией eval. По умолчанию: false.

    • preview <boolean> Определяет, выводит ли repl предварительный просмотр автодополнения и вывода или нет. По умолчанию: true с функцией eval по умолчанию и false в случае использования пользовательской функции eval. Если terminal ложно, то предварительного просмотра нет, и значение preview не имеет эффекта.

  • Возвращает: <repl.REPLServer>

Метод repl.start() создаёт и запускает экземпляр repl.REPLServer.

Если options — строка, то она задаёт подсказку для ввода:

js
import repl from 'node:repl'

// Подсказка в стиле Unix
repl.start('$ ')
js
const repl = require('node:repl')

// Подсказка в стиле Unix
repl.start('$ ')

REPL в Node.js

Сам Node.js использует модуль node:repl для предоставления собственного интерактивного интерфейса для выполнения JavaScript. Это можно сделать, запустив двоичный файл Node.js без передачи каких-либо аргументов (или передав аргумент -i):

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

Параметры переменных среды

Различные поведенческие характеристики REPL Node.js можно настраивать с помощью следующих переменных среды:

  • NODE_REPL_HISTORY: Если указан допустимый путь, постоянная история REPL будет сохранена в указанный файл, а не в .node_repl_history в домашнем каталоге пользователя. Установка этого значения в '' (пустая строка) отключит постоянную историю REPL. Пробелы будут удалены из значения. В операционных системах Windows переменные среды с пустыми значениями являются недопустимыми, поэтому для отключения постоянной истории REPL установите эту переменную в одно или несколько пробелов.
  • NODE_REPL_HISTORY_SIZE: Управляет количеством строк истории, которые будут сохраняться, если история доступна. Должно быть положительным числом. По умолчанию: 1000.
  • NODE_REPL_MODE: Может быть либо 'sloppy', либо 'strict'. По умолчанию: 'sloppy', что позволит запускать код в нестрогом режиме.

Постоянная история

По умолчанию REPL Node.js будет сохранять историю между сессиями node REPL, сохраняя вводимые данные в файл .node_repl_history, расположенный в домашнем каталоге пользователя. Это можно отключить, установив переменную среды NODE_REPL_HISTORY=''.

Использование REPL Node.js с расширенными текстовыми редакторами

Для расширенных текстовых редакторов запустите Node.js с переменной среды NODE_NO_READLINE=1. Это запустит основной и отладочный REPL в стандартных настройках терминала, что позволит использовать его с rlwrap.

Например, следующее можно добавить в файл .bashrc:

bash
alias node="env NODE_NO_READLINE=1 rlwrap node"

Запуск нескольких экземпляров REPL для одного запущенного экземпляра

Можно создавать и запускать несколько экземпляров REPL для одного запущенного экземпляра Node.js, которые используют один объект global, но имеют отдельные интерфейсы ввода-вывода.

Например, в следующем примере показаны отдельные REPL на stdin, Unix-сокете и TCP-сокете:

js
import net from 'node:net'
import repl from 'node:repl'
import process from 'node:process'

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)
js
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)

Запуск этого приложения из командной строки запустит REPL на stdin. Другие клиенты REPL могут подключаться через Unix-сокет или TCP-сокет. Например, telnet полезен для подключения к TCP-сокетам, а socat может использоваться для подключения как к Unix-, так и к TCP-сокетам.

Запустив REPL с сервера на основе Unix-сокета вместо stdin, можно подключаться к длительно работающему процессу Node.js без его перезапуска.

Пример запуска "полнофункционального" (terminal) REPL через экземпляры net.Server и net.Socket см.: https://gist.github.com/TooTallNate/2209310.

Пример запуска экземпляра REPL через curl(1) см.: https://gist.github.com/TooTallNate/2053342.

Этот пример предназначен исключительно для образовательных целей, чтобы продемонстрировать, как можно запускать REPL Node.js с использованием различных потоков ввода-вывода. Его не следует использовать в производственных средах или в любом контексте, где безопасность является проблемой, без дополнительных защитных мер. Если вам необходимо реализовать REPL в реальном приложении, рассмотрите альтернативные подходы, которые снижают эти риски, такие как использование безопасных механизмов ввода и избегание открытых сетевых интерфейсов.