var util = require('util') var EventEmitter = require('events').EventEmitter var StateMachine = function (rli, colors) { var questions var currentQuestion var answers var currentOptions var currentOptionsPointer var currentQuestionId var done EventEmitter.call(this) var showPrompt = function () { rli.write(colors.ANSWER) rli.prompt() } this.onKeypress = function (key) { if (!currentOptions || !key) { return } if (key.name === 'tab' || key.name === 'right' || key.name === 'down') { this.suggestNextOption() } else if (key.name === 'left' || key.name === 'up') { currentOptionsPointer = currentOptionsPointer + currentOptions.length - 2 this.suggestNextOption() } if (!key.ctrl && !key.meta && key.name !== 'enter' && key.name !== 'return') { key.name = 'escape' } } this.suggestNextOption = function () { if (!currentOptions) { return } currentOptionsPointer = (currentOptionsPointer + 1) % currentOptions.length rli._deleteLineLeft() rli._deleteLineRight() rli.write(currentOptions[currentOptionsPointer]) } this.kill = function () { currentOptions = null currentQuestionId = null rli.write('\n' + colors.RESET + '\n') rli.close() } this.onLine = function (line) { if (currentQuestionId) { rli.write(colors.RESET) line = line.trim().replace(colors.ANSWER, '').replace(colors.RESET, '') if (currentOptions) { currentOptionsPointer = currentOptions.indexOf(line) if (currentOptionsPointer === -1) { return } } if (line === '') { line = null } if (currentQuestion.boolean) { line = (line === 'yes' || line === 'true' || line === 'on') } if (line !== null && currentQuestion.validate) { currentQuestion.validate(line) } if (currentQuestion.multiple) { answers[currentQuestionId] = answers[currentQuestionId] || [] if (line !== null) { answers[currentQuestionId].push(line) showPrompt() if (currentOptions) { currentOptions.splice(currentOptionsPointer, 1) currentOptionsPointer = -1 } } else { this.nextQuestion() } } else { answers[currentQuestionId] = line this.nextQuestion() } } } this.nextQuestion = function () { currentQuestion = questions.shift() while (currentQuestion && currentQuestion.condition && !currentQuestion.condition(answers)) { currentQuestion = questions.shift() } this.emit('next_question', currentQuestion) if (currentQuestion) { currentQuestionId = null rli.write('\n' + colors.question(currentQuestion.question) + '\n') rli.write(currentQuestion.hint + '\n') showPrompt() currentOptions = currentQuestion.options || null currentOptionsPointer = -1 currentQuestionId = currentQuestion.id this.suggestNextOption() } else { currentQuestionId = null currentOptions = null // end this.kill() done(answers) } } this.process = function (_questions, _done) { questions = _questions answers = {} done = _done this.nextQuestion() } } util.inherits(StateMachine, EventEmitter) module.exports = StateMachine