state_machine.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. 'use strict'
  2. const logQueue = require('./log-queue')
  3. var questions
  4. var currentQuestion
  5. var answers
  6. var currentOptions
  7. var currentOptionsPointer
  8. var currentQuestionId
  9. var done
  10. class StateMachine {
  11. constructor (rli, colors) {
  12. this.rli = rli
  13. this.colors = colors
  14. }
  15. showPrompt () {
  16. this.rli.write(this.colors.ANSWER)
  17. this.rli.prompt()
  18. }
  19. onKeypress (key) {
  20. if (!currentOptions || !key) {
  21. return
  22. }
  23. if (key.name === 'tab' || key.name === 'right' || key.name === 'down') {
  24. this.suggestOption(currentOptionsPointer + 1)
  25. } else if (key.name === 'left' || key.name === 'up') {
  26. this.suggestOption(currentOptionsPointer - 1)
  27. }
  28. if (!key.ctrl && !key.meta && key.name !== 'enter' && key.name !== 'return') {
  29. key.name = 'escape'
  30. }
  31. }
  32. suggestOption (index) {
  33. if (!currentOptions) {
  34. return
  35. }
  36. if (index === -1) {
  37. currentOptionsPointer = currentOptions.length - 1
  38. } else if (index === currentOptions.length) {
  39. currentOptionsPointer = 0
  40. } else {
  41. currentOptionsPointer = index
  42. }
  43. this.rli._deleteLineLeft()
  44. this.rli._deleteLineRight()
  45. this.rli.write(currentOptions[currentOptionsPointer])
  46. }
  47. kill () {
  48. currentOptions = null
  49. currentQuestionId = null
  50. this.rli.write('\n' + this.colors.RESET + '\n')
  51. this.rli.close()
  52. }
  53. onLine (line) {
  54. if (currentQuestionId) {
  55. this.rli.write(this.colors.RESET)
  56. line = line.trim().replace(this.colors.ANSWER, '').replace(this.colors.RESET, '')
  57. if (currentOptions) {
  58. currentOptionsPointer = currentOptions.indexOf(line)
  59. if (currentOptionsPointer === -1) {
  60. return
  61. }
  62. }
  63. if (line === '') {
  64. line = null
  65. }
  66. if (currentQuestion.boolean) {
  67. line = (line === 'yes' || line === 'true' || line === 'on')
  68. }
  69. if (line !== null && currentQuestion.validate) {
  70. currentQuestion.validate(line)
  71. }
  72. if (currentQuestion.multiple) {
  73. answers[currentQuestionId] = answers[currentQuestionId] || []
  74. if (line !== null) {
  75. answers[currentQuestionId].push(line)
  76. this.showPrompt()
  77. if (currentOptions) {
  78. currentOptions.splice(currentOptionsPointer, 1)
  79. currentOptionsPointer = -1
  80. }
  81. } else {
  82. this.nextQuestion()
  83. }
  84. } else {
  85. answers[currentQuestionId] = line
  86. this.nextQuestion()
  87. }
  88. }
  89. }
  90. nextQuestion () {
  91. currentQuestion = questions.shift()
  92. while (currentQuestion && currentQuestion.condition && !currentQuestion.condition(answers)) {
  93. currentQuestion = questions.shift()
  94. }
  95. logQueue.printLogQueue()
  96. if (currentQuestion) {
  97. currentQuestionId = null
  98. this.rli.write('\n' + this.colors.question(currentQuestion.question) + '\n')
  99. this.rli.write(currentQuestion.hint + '\n')
  100. this.showPrompt()
  101. currentOptions = currentQuestion.options || null
  102. currentQuestionId = currentQuestion.id
  103. this.suggestOption(0)
  104. } else {
  105. this.kill()
  106. done(answers)
  107. }
  108. }
  109. process (_questions, _done) {
  110. questions = _questions
  111. answers = {}
  112. done = _done
  113. this.nextQuestion()
  114. }
  115. }
  116. module.exports = StateMachine