Spec-Zone.ru › Node.js

REPL

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

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

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

Модули JavaScript
import repl from 'node:repl';
CommonJS
const repl = require('node:repl');

Архитектура и возможности

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

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

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

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

  • .break: При вводе многострочного выражения введите команду .break (или нажмите Ctrl+C), чтобы прервать дальнейший ввод или обработку этого выражения.
  • .clear: Сбрасывает context REPL до пустого объекта и удаляет вводимое многострочное выражение.
  • .exit: Закрывает поток ввода-вывода, вызывая выход из 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!'
>
consolecopy

Следующие сочетания клавиш в 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
consolecopy

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

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

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

Модули JavaScript
import repl from 'node:repl';
const msg = 'message';

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

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

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

$ node repl_test.js
> m
'message'
consolecopy

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

Модули JavaScript
import repl from 'node:repl';
const msg = 'message';

const r = repl.start('> ');
Object.defineProperty(r.context, 'm', {
  configurable: false,
  enumerable: true,
  value: msg,
});
CommonJS
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');
consolecopy
Глобальные необработанные исключения
История
Версия Изменения
v12.3.0

Событие 'uncaughtException' теперь генерируется, если repl используется как отдельная программа.

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

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

  • Необработанные исключения генерируют событие 'uncaughtException' только в отдельной программе REPL. Добавление обработчика этого события в REPL, запущенный внутри другой программы Node.js, приводит к ошибке ERR_INVALID_REPL_INPUT.

    const r = repl.start();
    
    r.write('process.on("uncaughtException", () => console.log("Foobar"));\n');
    // Output stream includes:
    //   TypeError [ERR_INVALID_REPL_INPUT]: Listeners for `uncaughtException`
    //   cannot be used in the REPL
    
    r.close();
    jscopy
  • Попытка использовать process.setUncaughtExceptionCaptureCallback() приводит к ошибке ERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTURE.

Присваивание переменной _ (подчёркивание)
История
Версия Изменения
v9.8.0

Добавлена поддержка _error.

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

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

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

> throw new Error('foo');
Uncaught Error: foo
> _error.message
'foo'
consolecopy
Ключевое слово 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
consolecopy

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

Например:

> const m = await Promise.resolve(123)
undefined
> m
123
> m = await Promise.resolve(234)
234
// redeclaring the constant does error
> const m = await Promise.resolve(345)
Uncaught SyntaxError: Identifier 'm' has already been declared
consolecopy

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

Обратный поиск по истории

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

REPL поддерживает двунаправленный обратный поиск по истории, аналогичный ZSH. Для поиска назад нажмите Ctrl+R, а для поиска вперёд — Ctrl+S.

Повторяющиеся записи истории пропускаются.

Записи принимаются при нажатии любой клавиши, не относящейся к обратному поиску. Поиск можно отменить нажатием Esc или Ctrl+C.

При смене направления немедленно выполняется поиск следующей записи в выбранном направлении, начиная с текущей позиции.

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

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

Функция вычисления принимает следующие четыре аргумента:

  • code <string> Код для выполнения (например, 1 + 1).
  • context <Object> Контекст, в котором выполняется код. В зависимости от параметра useGlobal это может быть контекст JavaScript global или контекст, относящийся к экземпляру REPL.
  • replResourceName <string> Идентификатор ресурса REPL, связанного с текущим вычислением кода. Может быть полезен для отладки.
  • callback <Function> Функция, вызываемая после завершения вычисления кода. Функция обратного вызова принимает два параметра:
    • Объект ошибки, передаваемый при возникновении ошибки во время вычисления, или null/undefined, если ошибок не было.
    • Результат вычисления кода (не имеет значения, если передана ошибка).

В следующем примере показан REPL, который возводит заданное число в квадрат; если введённое значение не является числом, вместо этого выводится ошибка:

Модули JavaScript
import repl from 'node:repl';

function byThePowerOfTwo(number) {
  return number * number;
}

function myEval(code, context, replResourceName, callback) {
  if (isNaN(code)) {
    callback(new Error(`${code.trim()} is not a number`));
  } else {
    callback(null, byThePowerOfTwo(code));
  }
}

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

function byThePowerOfTwo(number) {
  return number * number;
}

function myEval(code, context, replResourceName, callback) {
  if (isNaN(code)) {
    callback(new Error(`${code.trim()} is not a number`));
  } else {
    callback(null, byThePowerOfTwo(code));
  }
}

repl.start({ prompt: 'Enter a number: ', 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;
}
jscopy

Настройка вывода REPL

По умолчанию экземпляры repl.REPLServer форматируют вывод с помощью метода util.inspect(), прежде чем записать его в предоставленный поток Writable (по умолчанию process.stdout). По умолчанию параметр проверки showProxy имеет значение true, а параметр colors имеет значение true в зависимости от параметра useColors REPL.

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

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

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

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

Модули JavaScript
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();
}
CommonJS
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.

Модули JavaScript
import repl from 'node:repl';

const options = { useColors: true };

const firstInstance = repl.start(options);
const secondInstance = new repl.REPLServer(options);
CommonJS
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, пользователь дважды нажал Ctrl+C, чтобы отправить сигнал SIGINT, или нажал Ctrl+D, чтобы отправить сигнал 'end' во входной поток. Функция обратного вызова обработчика вызывается без аргументов.

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

Событие: 'reset'

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

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

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

Модули JavaScript
import repl from 'node:repl';

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

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

r.on('reset', initializeContext);
CommonJS
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'
>
consolecopy

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:

Модули JavaScript
import repl from '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();
});
CommonJS
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!
consolecopy

replServer.displayPrompt([preserveCursor])

Добавлено в: v0.1.91
  • preserveCursor <boolean>

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

При вводе нескольких строк вместо «приглашения» выводится символ конвейера '|'.

Если preserveCursor имеет значение true, позиция курсора не будет сброшена в 0.

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

replServer.clearBufferedCommand()

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

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

replServer.setupHistory(historyConfig, callback)

Добавлено в: v11.10.0
История
Версия Изменения
v24.2.0

Параметр historyConfig обновлён: теперь он принимает объект со свойствами filePath, size, removeHistoryDuplicates и onHistoryFileLoaded.

  • historyConfig <Object> | <string> путь к файлу истории. Если это строка, она задаёт путь к файлу истории. Если это объект, он может иметь следующие свойства:
    • filePath <string> путь к файлу истории
    • size <number> Максимальное количество сохраняемых строк истории. Чтобы отключить историю, установите это значение в 0. Этот параметр имеет смысл, только если пользователь или внутренняя проверка output установили terminal в значение true; в противном случае механизм кэширования истории вообще не инициализируется. По умолчанию: 30.
    • removeHistoryDuplicates <boolean> Если значение true равно true, при добавлении новой строки ввода в список истории её более старая дублирующая запись удаляется из списка. По умолчанию: false.
    • onHistoryFileLoaded <Function> вызывается, когда запись истории готова или произошла ошибка
      • err <Error>
      • repl <repl.REPLServer>
  • callback <Function> вызывается, когда запись истории готова или произошла ошибка (необязательно, если задано как onHistoryFileLoaded в historyConfig)
    • err <Error>
    • repl <repl.REPLServer>

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

repl.builtinModules

Добавлено в: v14.5.0Устарело в: v24.0.0, v22.16.0

Стабильность: 0 - Устарело. Вместо этого используйте module.builtinModules.

  • Тип: <string[]>

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

Доступна автоматическая миграция (исходный код):

npx codemod@latest @nodejs/repl-builtin-modules
bashcopy

repl.start([options])

Добавлено в: v0.1.91
История
Версия Изменения
v25.9.0

Добавлен параметр handleError.

v24.1.0

Добавлена возможность добавлять, редактировать и удалять многострочные команды при добавлении многострочной команды.

v24.0.0

Теперь для обозначения многострочного ввода используется "|" вместо "...". Добавлена поддержка многострочной истории. Теперь можно «исправлять» многострочные команды с синтаксическими ошибками: для этого нужно открыть историю и отредактировать команду. При просмотре многострочной истории из старой версии Node.js структура многострочного ввода не сохраняется.

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 является необязательным.

  • 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 CLI Node.js задаёт этому параметру значение true. По умолчанию: false.
    • ignoreUndefined <boolean> Если true, указывает, что средство вывода по умолчанию не будет выводить возвращаемое значение команды, если оно вычисляется как 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, например при нажатии Ctrl+C. Этот параметр нельзя использовать вместе с пользовательской функцией eval. По умолчанию: false.
    • preview <boolean> Определяет, выводит ли REPL подсказки автодополнения и предварительный просмотр результатов. По умолчанию: true при использовании функции eval по умолчанию и false при использовании пользовательской функции eval. Если terminal имеет ложное значение, предварительный просмотр не выводится, а значение preview не влияет на поведение.
    • handleError <Function> Эта функция настраивает обработку ошибок в REPL. Она получает выброшенное исключение в качестве первого аргумента и должна синхронно вернуть одно из следующих значений:
      • 'print' для вывода ошибки в поток вывода (поведение по умолчанию).
      • 'ignore' для пропуска всей оставшейся обработки ошибок.
      • 'unhandled' для обработки исключения как полностью необработанного. В этом случае ошибка будет передана обработчикам исключений уровня процесса, например событию 'uncaughtException'. Использование значения 'unhandled' может быть желательным или нежелательным в ситуациях, когда экземпляр REPLServer закрыт, в зависимости от конкретного сценария.
  • Возвращает: <repl.REPLServer>

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

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

Модули JavaScript
import repl from 'node:repl';

// a Unix style prompt
repl.start('$ ');
CommonJS
const repl = require('node:repl');

// a Unix style prompt
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
consolecopy

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

Различные аспекты поведения 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 сохраняет историю между сеансами REPL node, записывая введённые данные в файл .node_repl_history, расположенный в домашнем каталоге пользователя. Это можно отключить, задав переменную среды NODE_REPL_HISTORY=''.

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

Для работы с продвинутыми редакторами строк запустите Node.js с переменной среды NODE_NO_READLINE=1. Основная REPL и REPL отладчика будут запущены в каноническом режиме терминала, что позволит использовать rlwrap.

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

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

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

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

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

Модули JavaScript
import net from 'node:net';
import repl from 'node:repl';
import process from 'node:process';
import fs from 'node:fs';

let connections = 0;

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

const unixSocketPath = '/tmp/node-repl-sock';

// If the socket file already exists let's remove it
fs.rmSync(unixSocketPath, { force: true });

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

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

let connections = 0;

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

const unixSocketPath = '/tmp/node-repl-sock';

// If the socket file already exists let's remove it
fs.rmSync(unixSocketPath, { force: true });

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

net.createServer((socket) => {
  connections += 1;
  repl.start({
    prompt: 'Node.js via TCP socket> ',
    useGlobal: true,
    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, не перезапуская его.

Примеры

Полнофункциональная «терминальная» REPL через net.Server и net.Socket

В этом примере показано, как запустить «полнофункциональную» (терминальную) REPL с помощью net.Server и net.Socket

Следующий скрипт запускает HTTP-сервер на порту 1337, который позволяет клиентам устанавливать сокетные соединения с его экземпляром REPL.

Модули JavaScript
// repl-server.js
import repl from 'node:repl';
import net from 'node:net';

net
  .createServer((socket) => {
    const r = repl.start({
      prompt: `socket ${socket.remoteAddress}:${socket.remotePort}> `,
      input: socket,
      output: socket,
      terminal: true,
      useGlobal: false,
    });
    r.on('exit', () => {
      socket.end();
    });
    r.context.socket = socket;
  })
  .listen(1337);
CommonJS
// repl-server.js
const repl = require('node:repl');
const net = require('node:net');

net
  .createServer((socket) => {
    const r = repl.start({
      prompt: `socket ${socket.remoteAddress}:${socket.remotePort}> `,
      input: socket,
      output: socket,
      terminal: true,
      useGlobal: false,
    });
    r.on('exit', () => {
      socket.end();
    });
    r.context.socket = socket;
  })
  .listen(1337);

Следующий скрипт реализует клиент, который может установить сокетное соединение с описанным выше сервером через порт 1337.

Модули JavaScript
// repl-client.js
import net from 'node:net';
import process from 'node:process';

const sock = net.connect(1337);

process.stdin.pipe(sock);
sock.pipe(process.stdout);

sock.on('connect', () => {
  process.stdin.resume();
  process.stdin.setRawMode(true);
});

sock.on('close', () => {
  process.stdin.setRawMode(false);
  process.stdin.pause();
  sock.removeListener('close', done);
});

process.stdin.on('end', () => {
  sock.destroy();
  console.log();
});

process.stdin.on('data', (b) => {
  if (b.length === 1 && b[0] === 4) {
    process.stdin.emit('end');
  }
});
CommonJS
// repl-client.js
const net = require('node:net');

const sock = net.connect(1337);

process.stdin.pipe(sock);
sock.pipe(process.stdout);

sock.on('connect', () => {
  process.stdin.resume();
  process.stdin.setRawMode(true);
});

sock.on('close', () => {
  process.stdin.setRawMode(false);
  process.stdin.pause();
  sock.removeListener('close', done);
});

process.stdin.on('end', () => {
  sock.destroy();
  console.log();
});

process.stdin.on('data', (b) => {
  if (b.length === 1 && b[0] === 4) {
    process.stdin.emit('end');
  }
});

Чтобы запустить пример, откройте на компьютере два разных терминала, запустите сервер командой node repl-server.js в одном терминале, а node repl-client.js — в другом.

Исходный код из https://gist.github.com/TooTallNate/2209310.

REPL через curl

В этом примере показано, как запустить экземпляр REPL через curl()

Следующий скрипт запускает HTTP-сервер на порту 8000, который принимает соединения, установленные с помощью curl().

Модули JavaScript
import http from 'node:http';
import repl from 'node:repl';

const server = http.createServer((req, res) => {
  res.setHeader('content-type', 'multipart/octet-stream');

  repl.start({
    prompt: 'curl repl> ',
    input: req,
    output: res,
    terminal: false,
    useColors: true,
    useGlobal: false,
  });
});

server.listen(8000);
CommonJS
const http = require('node:http');
const repl = require('node:repl');

const server = http.createServer((req, res) => {
  res.setHeader('content-type', 'multipart/octet-stream');

  repl.start({
    prompt: 'curl repl> ',
    input: req,
    output: res,
    terminal: false,
    useColors: true,
    useGlobal: false,
  });
});

server.listen(8000);

После запуска приведённого выше скрипта можно использовать curl() для подключения к серверу и его экземпляру REPL, выполнив команду curl --no-progress-meter -sSNT. localhost:8000.

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

Исходный код из https://gist.github.com/TooTallNate/2053342.

© Joyent, Inc. and other Node contributors
Licensed under the MIT License.
Node.js is a trademark of Joyent, Inc. and is used with its permission.
We are not endorsed by or affiliated with Joyent.
https://nodejs.org/api/repl.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API