gather-user-responses.ts 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. import fs from 'fs-extra';
  2. import Handlebars from 'handlebars';
  3. import path from 'path';
  4. import prompts, { PromptObject } from 'prompts';
  5. import { DbType, UserResponses } from './types';
  6. // tslint:disable:no-console
  7. /**
  8. * Prompts the user to determine how the new Vendure app should be configured.
  9. */
  10. export async function gatherUserResponses(root: string): Promise<UserResponses> {
  11. function onSubmit(prompt: PromptObject, answer: any) {
  12. if (prompt.name === 'dbType') {
  13. dbType = answer;
  14. }
  15. }
  16. let dbType: DbType;
  17. const answers = await prompts(
  18. [
  19. {
  20. type: 'select',
  21. name: 'dbType',
  22. message: 'Which database are you using?',
  23. choices: [
  24. { title: 'MySQL / MariaDB', value: 'mysql' },
  25. { title: 'Postgres', value: 'postgres' },
  26. { title: 'SQLite', value: 'sqlite' },
  27. { title: 'SQL.js', value: 'sqljs' },
  28. // Don't show these until they have been tested.
  29. // { title: 'MS SQL Server', value: 'mssql' },
  30. // { title: 'Oracle', value: 'oracle' },
  31. ],
  32. initial: 0 as any,
  33. },
  34. {
  35. type: (() => (dbType === 'sqlite' || dbType === 'sqljs' ? null : 'text')) as any,
  36. name: 'dbHost',
  37. message: `What's the database host address?`,
  38. initial: '192.168.99.100',
  39. },
  40. {
  41. type: (() => (dbType === 'sqlite' || dbType === 'sqljs' ? null : 'text')) as any,
  42. name: 'dbPort',
  43. message: `What port is the database listening on?`,
  44. initial: (() => defaultDBPort(dbType)) as any,
  45. },
  46. {
  47. type: (() => (dbType === 'sqlite' || dbType === 'sqljs' ? null : 'text')) as any,
  48. name: 'dbName',
  49. message: `What's the name of the database?`,
  50. initial: 'vendure',
  51. },
  52. {
  53. type: (() => (dbType === 'sqlite' || dbType === 'sqljs' ? null : 'text')) as any,
  54. name: 'dbUserName',
  55. message: `What's the database user name?`,
  56. initial: 'root',
  57. },
  58. {
  59. type: (() => (dbType === 'sqlite' || dbType === 'sqljs' ? null : 'password')) as any,
  60. name: 'dbPassword',
  61. message: `What's the database password?`,
  62. },
  63. {
  64. type: 'select',
  65. name: 'language',
  66. message: 'Which programming language will you be using?',
  67. choices: [{ title: 'TypeScript', value: 'ts' }, { title: 'JavaScript', value: 'js' }],
  68. initial: 0 as any,
  69. },
  70. {
  71. type: 'toggle',
  72. name: 'populateProducts',
  73. message: 'Populate with some sample product data?',
  74. initial: true,
  75. active: 'yes',
  76. inactive: 'no',
  77. },
  78. ],
  79. {
  80. onSubmit,
  81. onCancel() {
  82. /* */
  83. },
  84. },
  85. );
  86. if (!answers.language) {
  87. console.log('Setup aborted. No changes made');
  88. process.exit(0);
  89. }
  90. const {
  91. indexSource,
  92. indexWorkerSource,
  93. configSource,
  94. migrationSource,
  95. readmeSource,
  96. } = await generateSources(root, answers);
  97. return {
  98. indexSource,
  99. indexWorkerSource,
  100. configSource,
  101. migrationSource,
  102. readmeSource,
  103. usingTs: answers.language === 'ts',
  104. dbType: answers.dbType,
  105. populateProducts: answers.populateProducts,
  106. };
  107. }
  108. /**
  109. * Returns mock "user response" without prompting, for use in CI
  110. */
  111. export async function gatherCiUserResponses(root: string): Promise<UserResponses> {
  112. const ciAnswers = {
  113. dbType: 'sqlite' as const,
  114. dbHost: '',
  115. dbPort: '',
  116. dbName: 'vendure',
  117. dbUserName: '',
  118. dbPassword: '',
  119. language: 'ts',
  120. populateProducts: true,
  121. };
  122. const {
  123. indexSource,
  124. indexWorkerSource,
  125. configSource,
  126. migrationSource,
  127. readmeSource,
  128. } = await generateSources(root, ciAnswers);
  129. return {
  130. indexSource,
  131. indexWorkerSource,
  132. configSource,
  133. migrationSource,
  134. readmeSource,
  135. usingTs: ciAnswers.language === 'ts',
  136. dbType: ciAnswers.dbType,
  137. populateProducts: ciAnswers.populateProducts,
  138. };
  139. }
  140. /**
  141. * Create the server index, worker and config source code based on the options specified by the CLI prompts.
  142. */
  143. async function generateSources(
  144. root: string,
  145. answers: any,
  146. ): Promise<{
  147. indexSource: string;
  148. indexWorkerSource: string;
  149. configSource: string;
  150. migrationSource: string;
  151. readmeSource: string;
  152. }> {
  153. const assetPath = (fileName: string) => path.join(__dirname, '../assets', fileName);
  154. const templateContext = {
  155. ...answers,
  156. name: path.basename(root),
  157. isTs: answers.language === 'ts',
  158. isSQLite: answers.dbType === 'sqlite',
  159. isSQLjs: answers.dbType === 'sqljs',
  160. requiresConnection: answers.dbType !== 'sqlite' && answers.dbType !== 'sqljs',
  161. sessionSecret: Math.random()
  162. .toString(36)
  163. .substr(3),
  164. };
  165. const configTemplate = await fs.readFile(assetPath('vendure-config.hbs'), 'utf-8');
  166. const configSource = Handlebars.compile(configTemplate)(templateContext);
  167. const indexTemplate = await fs.readFile(assetPath('index.hbs'), 'utf-8');
  168. const indexSource = Handlebars.compile(indexTemplate)(templateContext);
  169. const indexWorkerTemplate = await fs.readFile(assetPath('index-worker.hbs'), 'utf-8');
  170. const indexWorkerSource = Handlebars.compile(indexWorkerTemplate)(templateContext);
  171. const migrationTemplate = await fs.readFile(assetPath('migration.hbs'), 'utf-8');
  172. const migrationSource = Handlebars.compile(migrationTemplate)(templateContext);
  173. const readmeTemplate = await fs.readFile(assetPath('readme.hbs'), 'utf-8');
  174. const readmeSource = Handlebars.compile(readmeTemplate)(templateContext);
  175. return { indexSource, indexWorkerSource, configSource, migrationSource, readmeSource };
  176. }
  177. function defaultDBPort(dbType: DbType): number {
  178. switch (dbType) {
  179. case 'mysql':
  180. return 3306;
  181. case 'postgres':
  182. return 5432;
  183. case 'mssql':
  184. return 1433;
  185. case 'oracle':
  186. return 1521;
  187. default:
  188. return 3306;
  189. }
  190. }