REPL
[Стабильно: 2 - Стабильно]
Стабильно: 2 Стабильность: 2 - Стабильно
Исходный код: lib/repl.js
Модуль node:repl
предоставляет реализацию цикла «читать-выполнять-печатать-цикл» (REPL), доступную как в виде отдельной программы, так и для включения в другие приложения. Доступ к нему можно получить с помощью:
import repl from 'node:repl'
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
: Сбрасывает контекст REPLcontext
до пустого объекта и очищает любой вводимый многострочный оператор..exit
: Закрывает поток ввода-вывода, вызывая выход из REPL..help
: Показывает этот список специальных команд..save
: Сохраняет текущую сессию REPL в файл:\> .save ./file/to/save.js
.load
: Загружает файл в текущую сессию REPL.\> .load ./file/to/load.js
.editor
: Входит в режим редактора (+ для завершения, Ctrl+C для отмены).
> .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:
> 1 + 1
2
> const m = 2
undefined
> m + 1
3
Если не указано иное в блоках или функциях, переменные, объявленные неявно или с помощью ключевых слов const
, let
или var
, объявляются в глобальной области видимости.
Глобальная и локальная область видимости
Оценщик по умолчанию предоставляет доступ ко всем переменным, существующим в глобальной области видимости. Можно явно предоставить переменную REPL, присвоив её объекту context
, связанному с каждым REPLServer
:
import repl from 'node:repl'
const msg = 'message'
repl.start('> ').context.m = msg
const repl = require('node:repl')
const msg = 'message'
repl.start('> ').context.m = msg
Свойства объекта context
отображаются как локальные внутри REPL:
$ node repl_test.js
> m
'message'
Свойства контекста по умолчанию не являются доступными только для чтения. Для указания глобальных переменных, доступных только для чтения, свойства контекста должны быть определены с помощью Object.defineProperty()
:
import repl from 'node:repl'
const msg = 'message'
const r = repl.start('> ')
Object.defineProperty(r.context, 'm', {
configurable: false,
enumerable: true,
value: msg,
})
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');
Глобальные неперехваченные исключения
[История]
Версия | Изменения |
---|---|
v12.3.0 | Событие 'uncaughtException' теперь срабатывает, если REPL используется как отдельная программа. |
REPL использует модуль domain
для перехвата всех неперехваченных исключений для данного сеанса REPL.
Использование модуля domain
в REPL имеет следующие побочные эффекты:
- Неперехваченные исключения генерируют событие
'uncaughtException'
только в автономном REPL. Добавление обработчика для этого события в REPL внутри другой программы Node.js приводит к ошибкеERR_INVALID_REPL_INPUT
. - Попытка использовать
process.setUncaughtExceptionCaptureCallback()
вызывает ошибкуERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTURE
.
Присваивание переменной _
(подчеркивание)
[История]
Версия | Изменения |
---|---|
v9.8.0 | Добавлена поддержка _error . |
По умолчанию интерпретатор по умолчанию присваивает результат последнего вычисленного выражения специальной переменной _
(подчеркивание). Явное присваивание значения _
отключает это поведение.
> [ 'a', 'b', 'c' ]
[ 'a', 'b', 'c' ]
> _.length
3
> _ += 1
Присваивание выражения _ теперь отключено.
4
> 1 + 1
2
> _
4
Аналогично, _error
будет ссылаться на последнюю обнаруженную ошибку, если таковая имелась. Явное присваивание значения _error
отключает это поведение.
> throw new Error('foo');
Неперехваченная ошибка: foo
> _error.message
'foo'
Ключевое слово await
Поддержка ключевого слова await
включена на верхнем уровне.
> 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
.
Например:
> 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, который возводит заданное число в квадрат:
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 })
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
в предоставленную функцию обратного вызова:
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()
.
> util.inspect.replDefaults.compact = false;
false
> [1]
[
1
]
>
Для полной настройки вывода экземпляра repl.REPLServer
передайте новую функцию для опции writer
при создании. Например, в следующем примере любой входной текст просто преобразуется в верхний регистр:
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()
}
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
options
<Object> | <string> См.repl.start()
- Расширяет: <readline.Interface>
Экземпляры repl.REPLServer
создаются с помощью метода repl.start()
или напрямую с помощью JavaScript-ключавого слова new
.
import repl from 'node:repl'
const options = { useColors: true }
const firstInstance = repl.start(options)
const secondInstance = new repl.REPLServer(options)
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'
во входном потоке. Обратный вызов прослушивателя вызывается без аргументов.
replServer.on('exit', () => {
console.log('Получено событие "exit" от repl!')
process.exit()
})
Событие: 'reset'
Добавлено в: v0.11.0
Событие 'reset'
генерируется при сбросе контекста REPL. Это происходит всякий раз, когда команда .clear
поступает в качестве входных данных, если только REPL не использует стандартный интерпретатор и экземпляр repl.REPLServer
не был создан с параметром useGlobal
, установленным в значение true
. Обратный вызов прослушивателя будет вызван со ссылкой на объект context
в качестве единственного аргумента.
Это может использоваться в основном для повторной инициализации контекста REPL до некоторого предопределенного состояния:
import repl from 'node:repl'
function initializeContext(context) {
context.m = 'test'
}
const r = repl.start({ prompt: '> ' })
initializeContext(r.context)
r.on('reset', initializeContext)
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
Очистка контекста...
> 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:
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()
})
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:
> .sayhello Node.js User
Привет, Node.js User!
> .saybye
До свидания!
replServer.displayPrompt([preserveCursor])
Добавлен в: v0.1.91
preserveCursor
<boolean>
Метод 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> вызывается, когда запись истории готова или при ошибкеerr
<Error>repl
<repl.REPLServer>
Инициализирует файл журнала истории для экземпляра 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 |
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> Функция, используемая для вычисления каждой введённой строки. По умолчанию: асинхронный обёртку для функции JavaScripteval()
. Функцияeval
может выдавать ошибкуrepl.Recoverable
, чтобы указать, что ввод был неполным, и запросить дополнительные строки.useColors
<boolean> Еслиtrue
, указывает, что функцияwriter
по умолчанию должна включать стилизацию ANSI-цветов в вывод REPL. Если предоставлена пользовательская функцияwriter
, это не имеет эффекта. По умолчанию: проверка поддержки цвета в потокеoutput
, если значениеterminal
экземпляра REPL равноtrue
.useGlobal
<boolean> Еслиtrue
, указывает, что функция вычисления по умолчанию будет использовать JavaScriptglobal
в качестве контекста, а не создавать новый отдельный контекст для экземпляра 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
— строка, то она задаёт подсказку для ввода:
import repl from 'node:repl'
// Подсказка в стиле Unix
repl.start('$ ')
const repl = require('node:repl')
// Подсказка в стиле Unix
repl.start('$ ')
REPL в Node.js
Сам Node.js использует модуль node:repl
для предоставления собственного интерактивного интерфейса для выполнения JavaScript. Это можно сделать, запустив двоичный файл Node.js без передачи каких-либо аргументов (или передав аргумент -i
):
$ 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
:
alias node="env NODE_NO_READLINE=1 rlwrap node"
Запуск нескольких экземпляров REPL для одного запущенного экземпляра
Можно создавать и запускать несколько экземпляров REPL для одного запущенного экземпляра Node.js, которые используют один объект global
, но имеют отдельные интерфейсы ввода-вывода.
Например, в следующем примере показаны отдельные REPL на stdin
, Unix-сокете и TCP-сокете:
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)
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 в реальном приложении, рассмотрите альтернативные подходы, которые снижают эти риски, такие как использование безопасных механизмов ввода и избегание открытых сетевых интерфейсов.