shared-prompts.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import { cancel, isCancel, multiselect, select, spinner, text } from '@clack/prompts';
  2. import { pascalCase } from 'change-case';
  3. import { ClassDeclaration, Project } from 'ts-morph';
  4. import { getPluginClasses, getTsMorphProject } from '../utilities/ast-utils';
  5. import { VendurePluginDeclaration } from '../utilities/vendure-plugin-declaration';
  6. export async function getCustomEntityName(cancelledMessage: string) {
  7. const entityName = await text({
  8. message: 'What is the name of the custom entity?',
  9. initialValue: '',
  10. validate: input => {
  11. if (!input) {
  12. return 'The custom entity name cannot be empty';
  13. }
  14. const pascalCaseRegex = /^[A-Z][a-zA-Z0-9]*$/;
  15. if (!pascalCaseRegex.test(input)) {
  16. return 'The custom entity name must be in PascalCase, e.g. "ProductReview"';
  17. }
  18. },
  19. });
  20. if (isCancel(entityName)) {
  21. cancel(cancelledMessage);
  22. process.exit(0);
  23. }
  24. return pascalCase(entityName);
  25. }
  26. export async function analyzeProject(options: {
  27. providedVendurePlugin?: VendurePluginDeclaration;
  28. cancelledMessage?: string;
  29. }) {
  30. const providedVendurePlugin = options.providedVendurePlugin;
  31. let project = providedVendurePlugin?.classDeclaration.getProject();
  32. if (!providedVendurePlugin) {
  33. const projectSpinner = spinner();
  34. projectSpinner.start('Analyzing project...');
  35. await new Promise(resolve => setTimeout(resolve, 100));
  36. project = getTsMorphProject();
  37. projectSpinner.stop('Project analyzed');
  38. }
  39. return project as Project;
  40. }
  41. export async function selectPlugin(
  42. project: Project,
  43. cancelledMessage: string,
  44. ): Promise<VendurePluginDeclaration> {
  45. const pluginClasses = getPluginClasses(project);
  46. const targetPlugin = await select({
  47. message: 'To which plugin would you like to add the feature?',
  48. options: pluginClasses.map(c => ({
  49. value: c,
  50. label: c.getName() as string,
  51. })),
  52. maxItems: 10,
  53. });
  54. if (isCancel(targetPlugin)) {
  55. cancel(cancelledMessage);
  56. process.exit(0);
  57. }
  58. return new VendurePluginDeclaration(targetPlugin as ClassDeclaration);
  59. }
  60. export async function selectMultiplePluginClasses(
  61. project: Project,
  62. cancelledMessage: string,
  63. ): Promise<VendurePluginDeclaration[]> {
  64. const pluginClasses = getPluginClasses(project);
  65. const selectAll = await select({
  66. message: 'To which plugin would you like to add the feature?',
  67. options: [
  68. {
  69. value: 'all',
  70. label: 'All plugins',
  71. },
  72. {
  73. value: 'specific',
  74. label: 'Specific plugins (you will be prompted to select the plugins)',
  75. },
  76. ],
  77. });
  78. if (isCancel(selectAll)) {
  79. cancel(cancelledMessage);
  80. process.exit(0);
  81. }
  82. if (selectAll === 'all') {
  83. return pluginClasses.map(pc => new VendurePluginDeclaration(pc));
  84. }
  85. const targetPlugins = await multiselect({
  86. message: 'Select one or more plugins (use ↑, ↓, space to select)',
  87. options: pluginClasses.map(c => ({
  88. value: c,
  89. label: c.getName() as string,
  90. })),
  91. });
  92. if (isCancel(targetPlugins)) {
  93. cancel(cancelledMessage);
  94. process.exit(0);
  95. }
  96. return (targetPlugins as ClassDeclaration[]).map(pc => new VendurePluginDeclaration(pc));
  97. }