add-codegen.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. import { log, note, outro, spinner } from '@clack/prompts';
  2. import path from 'path';
  3. import { StructureKind } from 'ts-morph';
  4. import { CliCommand } from '../../../shared/cli-command';
  5. import { PackageJson } from '../../../shared/package-json-ref';
  6. import { analyzeProject, selectMultiplePluginClasses } from '../../../shared/shared-prompts';
  7. import { VendurePluginRef } from '../../../shared/vendure-plugin-ref';
  8. import { getRelativeImportPath } from '../../../utilities/ast-utils';
  9. import { CodegenConfigRef } from './codegen-config-ref';
  10. export interface AddCodegenOptions {
  11. plugin?: VendurePluginRef;
  12. }
  13. export const addCodegenCommand = new CliCommand({
  14. id: 'add-codegen',
  15. category: 'Project: Codegen',
  16. description: 'Set up GraphQL code generation',
  17. run: addCodegen,
  18. });
  19. async function addCodegen(options?: AddCodegenOptions) {
  20. const providedVendurePlugin = options?.plugin;
  21. const project = await analyzeProject({
  22. providedVendurePlugin,
  23. cancelledMessage: 'Add codegen cancelled',
  24. });
  25. const plugins = providedVendurePlugin
  26. ? [providedVendurePlugin]
  27. : await selectMultiplePluginClasses(project, 'Add codegen cancelled');
  28. const packageJson = new PackageJson(project);
  29. const installSpinner = spinner();
  30. installSpinner.start(`Installing dependencies...`);
  31. const packagesToInstall = [
  32. {
  33. pkg: '@graphql-codegen/cli',
  34. isDevDependency: true,
  35. },
  36. {
  37. pkg: '@graphql-codegen/typescript',
  38. isDevDependency: true,
  39. },
  40. ];
  41. if (plugins.some(p => p.hasUiExtensions())) {
  42. packagesToInstall.push({
  43. pkg: '@graphql-codegen/client-preset',
  44. isDevDependency: true,
  45. });
  46. }
  47. try {
  48. await packageJson.installPackages(packagesToInstall);
  49. } catch (e: any) {
  50. log.error(`Failed to install dependencies: ${e.message as string}.`);
  51. }
  52. installSpinner.stop('Dependencies installed');
  53. const configSpinner = spinner();
  54. configSpinner.start('Configuring codegen file...');
  55. await new Promise(resolve => setTimeout(resolve, 100));
  56. const codegenFile = new CodegenConfigRef(packageJson.getPackageRootDir());
  57. const rootDir = project.getDirectory('.');
  58. if (!rootDir) {
  59. throw new Error('Could not find the root directory of the project');
  60. }
  61. for (const plugin of plugins) {
  62. const relativePluginPath = getRelativeImportPath({
  63. from: rootDir,
  64. to: plugin.classDeclaration.getSourceFile(),
  65. });
  66. const generatedTypesPath = `${path.dirname(relativePluginPath)}/gql/generated.ts`;
  67. codegenFile.addEntryToGeneratesObject({
  68. name: `'${generatedTypesPath}'`,
  69. kind: StructureKind.PropertyAssignment,
  70. initializer: `{ plugins: ['typescript'] }`,
  71. });
  72. if (plugin.hasUiExtensions()) {
  73. const uiExtensionsPath = `${path.dirname(relativePluginPath)}/ui`;
  74. codegenFile.addEntryToGeneratesObject({
  75. name: `'${uiExtensionsPath}/gql/'`,
  76. kind: StructureKind.PropertyAssignment,
  77. initializer: `{
  78. preset: 'client',
  79. documents: '${uiExtensionsPath}/**/*.ts',
  80. presetConfig: {
  81. fragmentMasking: false,
  82. },
  83. }`,
  84. });
  85. }
  86. }
  87. packageJson.addScript('codegen', 'graphql-codegen --config codegen.ts');
  88. configSpinner.stop('Configured codegen file');
  89. await project.save();
  90. await codegenFile.save();
  91. const nextSteps = [
  92. `You can run codegen by doing the following:`,
  93. `1. Ensure your dev server is running`,
  94. `2. Run "npm run codegen"`,
  95. ];
  96. note(nextSteps.join('\n'));
  97. if (!providedVendurePlugin) {
  98. outro('✅ Codegen setup complete!');
  99. }
  100. }