prompts.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. // Utils
  2. const { get, set, unset } = require('@vue/cli-shared-utils')
  3. const { log } = require('../util/logger')
  4. let answers = {}
  5. let prompts = []
  6. function generatePromptError (value) {
  7. let message
  8. if (typeof value === 'string') {
  9. message = value
  10. } else {
  11. message = 'Invalid input'
  12. }
  13. return {
  14. message
  15. }
  16. }
  17. async function getEnabled (value) {
  18. const type = typeof value
  19. if (type === 'function') {
  20. const result = await value(answers)
  21. return !!result
  22. } else if (type === 'boolean') {
  23. return value
  24. } else {
  25. return true
  26. }
  27. }
  28. function validateInput (prompt, value) {
  29. const validate = prompt.raw.validate
  30. if (typeof validate === 'function') {
  31. return validate(value, answers)
  32. }
  33. return true
  34. }
  35. function getFilteredValue (prompt, value) {
  36. const filter = prompt.raw.filter
  37. if (typeof filter === 'function') {
  38. return filter(value)
  39. }
  40. return value
  41. }
  42. function getTransformedValue (prompt, value) {
  43. const transformer = prompt.raw.transformer
  44. if (typeof transformer === 'function') {
  45. return transformer(value, answers)
  46. }
  47. return value
  48. }
  49. function generatePromptChoice (prompt, data, defaultValue) {
  50. return {
  51. value: JSON.stringify(getTransformedValue(prompt, data.value)),
  52. name: data.name,
  53. checked: data.checked,
  54. disabled: data.disabled,
  55. isDefault: data.value === defaultValue
  56. }
  57. }
  58. async function getChoices (prompt) {
  59. const data = prompt.raw.choices
  60. if (!data) {
  61. return null
  62. }
  63. let result
  64. if (typeof data === 'function') {
  65. result = await data(answers)
  66. } else {
  67. result = data
  68. }
  69. let defaultValue
  70. if (prompt.type === 'list' || prompt.type === 'rawlist') {
  71. defaultValue = await getDefaultValue(prompt)
  72. }
  73. return result.map(
  74. item => generatePromptChoice(prompt, item, defaultValue)
  75. )
  76. }
  77. function setAnswer (id, value) {
  78. set(answers, id, value)
  79. }
  80. function removeAnswer (id) {
  81. unset(answers, id)
  82. }
  83. function generatePrompt (data) {
  84. return {
  85. id: data.name,
  86. type: data.type,
  87. visible: true,
  88. enabled: true,
  89. name: data.short || null,
  90. message: data.message,
  91. group: data.group || null,
  92. description: data.description || null,
  93. link: data.link || null,
  94. choices: null,
  95. value: null,
  96. valueChanged: false,
  97. error: null,
  98. tabId: data.tabId || null,
  99. raw: data
  100. }
  101. }
  102. async function updatePrompts () {
  103. for (const prompt of prompts) {
  104. const oldVisible = prompt.visible
  105. prompt.visible = await getEnabled(prompt.raw.when)
  106. prompt.choices = await getChoices(prompt)
  107. if (oldVisible !== prompt.visible && !prompt.visible) {
  108. removeAnswer(prompt.id)
  109. prompt.valueChanged = false
  110. } else if (prompt.visible && !prompt.valueChanged) {
  111. let value
  112. const answer = getAnswer(prompt.id)
  113. if (typeof answer !== 'undefined') {
  114. value = await getTransformedValue(prompt, answer)
  115. } else if (typeof prompt.raw.value !== 'undefined') {
  116. value = prompt.raw.value
  117. } else {
  118. value = await getDefaultValue(prompt)
  119. }
  120. prompt.rawValue = value
  121. prompt.value = JSON.stringify(value)
  122. const finalValue = await getFilteredValue(prompt, value)
  123. setAnswer(prompt.id, finalValue)
  124. }
  125. }
  126. log('Prompt answers', answers)
  127. }
  128. // Public API
  129. async function setAnswers (newAnswers) {
  130. answers = newAnswers
  131. await updatePrompts()
  132. }
  133. async function changeAnswers (cb) {
  134. cb(answers)
  135. await updatePrompts()
  136. }
  137. function getAnswers () {
  138. return answers
  139. }
  140. function getAnswer (id) {
  141. return get(answers, id)
  142. }
  143. async function reset (answers = {}) {
  144. prompts = []
  145. await setAnswers(answers)
  146. }
  147. function list () {
  148. return prompts
  149. }
  150. function add (data) {
  151. const prompt = generatePrompt(data)
  152. prompts.push(prompt)
  153. return prompt
  154. }
  155. async function start () {
  156. await updatePrompts()
  157. }
  158. function remove (id) {
  159. const index = prompts.findIndex(p => p.id === id)
  160. index !== -1 && prompts.splice(index, 1)
  161. }
  162. async function setValue ({ id, value }) {
  163. const prompt = findOne(id)
  164. if (!prompt) {
  165. console.warn(`Prompt '${prompt}' not found`)
  166. return null
  167. }
  168. const validation = await validateInput(prompt, value)
  169. if (validation !== true) {
  170. prompt.error = generatePromptError(validation)
  171. } else {
  172. prompt.error = null
  173. }
  174. prompt.rawValue = value
  175. const finalValue = await getFilteredValue(prompt, value)
  176. prompt.value = JSON.stringify(value)
  177. prompt.valueChanged = true
  178. setAnswer(prompt.id, finalValue)
  179. await updatePrompts()
  180. return prompt
  181. }
  182. function findOne (id) {
  183. return prompts.find(
  184. p => p.id === id
  185. )
  186. }
  187. async function getDefaultValue (prompt) {
  188. let defaultValue = prompt.raw.default
  189. if (typeof defaultValue === 'function') {
  190. defaultValue = await defaultValue(answers)
  191. }
  192. if (prompt.type === 'checkbox') {
  193. const choices = prompt.raw.choices
  194. if (choices) {
  195. return choices.filter(
  196. c => c.checked
  197. ).map(
  198. c => c.value
  199. )
  200. }
  201. } else if (prompt.type === 'confirm') {
  202. if (prompt.raw.checked) return true
  203. return defaultValue || false
  204. }
  205. return defaultValue
  206. }
  207. async function answerPrompt ({ id, value }, context) {
  208. await setValue({ id, value: JSON.parse(value) })
  209. return list()
  210. }
  211. module.exports = {
  212. setAnswers,
  213. changeAnswers,
  214. getAnswers,
  215. getAnswer,
  216. reset,
  217. list,
  218. add,
  219. remove,
  220. start,
  221. setValue,
  222. findOne,
  223. getDefaultValue,
  224. answerPrompt
  225. }