index.ts 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. #!/usr/bin/env node
  2. import * as path from 'node:path';
  3. import * as fs from 'node:fs';
  4. import { createOrEmptyTargetDirectory } from './utils/fsHelpers';
  5. import { getInputs } from './utils/getInputs';
  6. import { getLanguage } from './utils/getLanguage';
  7. import { logBanner, logDone, logStep } from './utils/getLogs';
  8. import { RenderContext, getRenderContext } from './utils/getRenderContext';
  9. import { renderTemplate } from './utils/renderTemplates';
  10. import {
  11. detectAnchorVersion,
  12. detectSolanaVersion,
  13. generateKeypair,
  14. patchSolanaDependencies,
  15. } from './utils/solanaCli';
  16. (async function init() {
  17. logBanner();
  18. // Get arguments from CLI and prompt.
  19. const language = getLanguage();
  20. const inputs = await getInputs(language);
  21. // Create or empty the target directory.
  22. createOrEmptyTargetDirectory(
  23. language,
  24. inputs.targetDirectoryName,
  25. inputs.shouldOverride
  26. );
  27. // Detect the Solana version.
  28. const solanaVersionDetected = await logStep(
  29. language.infos.detectSolanaVersion,
  30. () => detectSolanaVersion(language)
  31. );
  32. // Detect the Anchor version.
  33. let anchorVersionDetected: string | undefined;
  34. if (inputs.programFramework === 'anchor') {
  35. anchorVersionDetected = await logStep(
  36. language.infos.detectAnchorVersion,
  37. () => detectAnchorVersion(language)
  38. );
  39. }
  40. // Generate a keypair if needed.
  41. const programAddress =
  42. inputs.programAddress ??
  43. (await logStep(language.infos.generateKeypair, () => {
  44. const outfile = path.join(
  45. process.cwd(),
  46. inputs.targetDirectoryName,
  47. 'program',
  48. 'keypair.json'
  49. );
  50. return generateKeypair(language, outfile);
  51. }));
  52. // Get the args inputs, prompt inputs and computed values.
  53. const ctx = getRenderContext({
  54. language,
  55. inputs,
  56. programAddress,
  57. solanaVersionDetected,
  58. anchorVersionDetected,
  59. });
  60. // Render the templates.
  61. await logStep(
  62. language.infos.scaffold.replace(
  63. '$targetDirectory',
  64. inputs.targetDirectoryName
  65. ),
  66. async () => {
  67. renderTemplates(ctx);
  68. await patchSolanaDependencies(ctx);
  69. }
  70. );
  71. // Done.
  72. logDone(ctx);
  73. })().catch((e) => console.error(e));
  74. function renderTemplates(ctx: RenderContext) {
  75. const render = (templateName: string) => {
  76. const directory = path.resolve(ctx.templateDirectory, templateName);
  77. if (!fs.existsSync(directory)) return;
  78. renderTemplate(ctx, directory, ctx.targetDirectory);
  79. };
  80. render('base');
  81. render(`${ctx.programFramework}/base`);
  82. if (ctx.clients.length > 0) {
  83. render('clients/base');
  84. render(`${ctx.programFramework}/clients/base`);
  85. }
  86. ctx.clients.forEach((client) => {
  87. render(`clients/${client}`);
  88. render(`${ctx.programFramework}/clients/${client}`);
  89. });
  90. }