UNPKG

showandtell

Version:

A Javascript library providing debugger-like command-line interactivity for program state inspection and modification

118 lines (111 loc) 3.52 kB
'use strict' const readline = require('readline') /** * A container for a set of commands that also provides special quit and help * commands. It deals with user interaction and applying state changes between * commands. * * @param {Array[Command]} commands are the commands that the session should support * @public */ function Session (commands) { this.commands = commands || [] } /** * Start an interactive session with the user, with an initial state. * * @param {Object} state is the initial state to begin modifying * @returns a promise that resolves to the new state * @public */ Session.prototype.start = function (state) { return new Promise((resolve, reject) => { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: false }) rl.setPrompt('>>> ') rl.prompt() rl .on('line', (line) => { line = line.trim() if (line.slice(0, 4).toUpperCase() === 'QUIT') { // Special termination case rl.close() process.stdin.destroy() resolve(state) } else if (line.slice(0, 4).toUpperCase() === 'HELP') { // Get information about a specific command this._handleHelp(line) rl.prompt() } else { // Invoke a specific, registered command this._handleCommand(state, line, function (err, nextState) { if (err) { console.error(err) } else { state = nextState } rl.prompt() }) } }) .on('close', () => resolve(state)) }) } /** * Handle the specal help command by either listing available commands or * showing the help message for the command provided. * * @param {String} line is the line of user input, with "HELP ..." * @returns nothing * @private */ Session.prototype._handleHelp = function (line) { if (line.length > 4) { const cmdName = line.slice(4).trim().toUpperCase() const cmds = this.commands.filter((c) => c.name() === cmdName) if (cmds.length === 0) { console.error('No such command', cmdName) } else { console.log(cmds[0].help()) } } else { console.log('Input format: CMD argument1 "string argument2" argument3 ...') console.log('QUIT - \tExit the command loop') console.log('HELP\noptional command - \tThe name of a command to get information about. Optional') console.log(this.commands.map((c) => c.name()).join('\n')) } } /** * Handle a command other than QUIT or HELP that is expected to have been * registered to the session. The command will be found by name (uppercase) * and then the arguments (the rest of the input string) will be supplied. * * @param {Object} state is the state at the time the command is invoked * @param {String} input is the user input including the command name * @param {Function} next is a callback used to move on to accepting more input * @returns nothing * @private */ Session.prototype._handleCommand = function (state, input, next) { const firstSpace = input.indexOf(' ') let command = '' let argString = '' if (firstSpace < 1) { command = input.toUpperCase() } else { command = input.slice(0, firstSpace).toUpperCase() argString = input.slice(firstSpace).trim() } const cmds = this.commands.filter((c) => c.name() === command) if (cmds.length === 0) { console.error('No such command', command) } else { cmds[0].execute(state, argString, next) } } module.exports = { Session }