#!/usr/bin/env node import * as path from 'node:path'; import * as fs from 'node:fs'; import { createOrEmptyTargetDirectory } from './utils/fsHelpers'; import { getInputs } from './utils/getInputs'; import { getLanguage } from './utils/getLanguage'; import { logBanner, logDone, logStep } from './utils/getLogs'; import { RenderContext, getRenderContext } from './utils/getRenderContext'; import { renderTemplate } from './utils/renderTemplates'; import { detectAnchorVersion, detectSolanaVersion, generateKeypair, patchSolanaDependencies, } from './utils/solanaCli'; (async function init() { logBanner(); // Get arguments from CLI and prompt. const language = getLanguage(); const inputs = await getInputs(language); // Create or empty the target directory. createOrEmptyTargetDirectory( language, inputs.targetDirectoryName, inputs.shouldOverride ); // Detect the Solana version. const solanaVersionDetected = await logStep( language.infos.detectSolanaVersion, () => detectSolanaVersion(language) ); // Detect the Anchor version. let anchorVersionDetected: string | undefined; if (inputs.programFramework === 'anchor') { anchorVersionDetected = await logStep( language.infos.detectAnchorVersion, () => detectAnchorVersion(language) ); } // Generate a keypair if needed. const programAddress = inputs.programAddress ?? (await logStep(language.infos.generateKeypair, () => { const outfile = path.join( process.cwd(), inputs.targetDirectoryName, 'program', 'keypair.json' ); return generateKeypair(language, outfile); })); // Get the args inputs, prompt inputs and computed values. const ctx = getRenderContext({ language, inputs, programAddress, solanaVersionDetected, anchorVersionDetected, }); // Render the templates. await logStep( language.infos.scaffold.replace( '$targetDirectory', inputs.targetDirectoryName ), async () => { renderTemplates(ctx); await patchSolanaDependencies(ctx); } ); // Done. logDone(ctx); })().catch((e) => console.error(e)); function renderTemplates(ctx: RenderContext) { const render = (templateName: string) => { const directory = path.resolve(ctx.templateDirectory, templateName); if (!fs.existsSync(directory)) return; renderTemplate(ctx, directory, ctx.targetDirectory); }; render('base'); render(`${ctx.programFramework}/base`); if (ctx.clients.length > 0) { render('clients/base'); render(`${ctx.programFramework}/clients/base`); } ctx.clients.forEach((client) => { render(`clients/${client}`); render(`${ctx.programFramework}/clients/${client}`); }); }