diff --git a/packages/thirdweb/src/cli/commands/stylus/builder.ts b/packages/thirdweb/src/cli/commands/stylus/builder.ts index b6a6e63a41b..39616213eb6 100644 --- a/packages/thirdweb/src/cli/commands/stylus/builder.ts +++ b/packages/thirdweb/src/cli/commands/stylus/builder.ts @@ -3,6 +3,7 @@ import { existsSync, readFileSync } from "node:fs"; import { join } from "node:path"; import open from "open"; import ora, { type Ora } from "ora"; +import prompts from "prompts"; import { parse } from "toml"; import { createThirdwebClient } from "../../../client/client.js"; import { upload } from "../../../storage/upload.js"; @@ -95,15 +96,49 @@ async function buildStylus(spinner: Ora, secretKey?: string) { spinner.succeed("ABI generated."); // Step 4: Process the output - const contractName = extractContractNameFromExportAbi(abiContent); - if (!contractName) { + const parts = abiContent.split(/======= :/g).filter(Boolean); + const contractNames = extractContractNamesFromExportAbi(abiContent); + + let selectedContractName: string | undefined; + let selectedAbiContent: string | undefined; + + if (contractNames.length === 1) { + selectedContractName = contractNames[0]?.replace(/^I/, ""); + selectedAbiContent = parts[0]; + } else { + const response = await prompts({ + type: "select", + name: "contract", + message: "Select entrypoint:", + choices: contractNames.map((name, idx) => ({ + title: name, + value: idx, + })), + }); + + const selectedIndex = response.contract; + + if (typeof selectedIndex !== "number") { + spinner.fail("No contract selected."); + process.exit(1); + } + + selectedContractName = contractNames[selectedIndex]?.replace(/^I/, ""); + selectedAbiContent = parts[selectedIndex]; + } + + if (!selectedAbiContent) { + throw new Error("Entrypoint not found"); + } + + if (!selectedContractName) { spinner.fail("Error: Could not determine contract name from ABI output."); process.exit(1); } let cleanedAbi = ""; try { - const jsonMatch = abiContent.match(/\[.*\]/s); + const jsonMatch = selectedAbiContent.match(/\[.*\]/s); if (jsonMatch) { cleanedAbi = jsonMatch[0]; } else { @@ -125,7 +160,7 @@ async function buildStylus(spinner: Ora, secretKey?: string) { }, settings: { compilationTarget: { - "src/main.rs": contractName, + "src/main.rs": selectedContractName, }, }, sources: {}, @@ -152,12 +187,12 @@ async function buildStylus(spinner: Ora, secretKey?: string) { client, files: [ { - name: contractName, + name: selectedContractName, metadataUri, bytecodeUri, analytics: { command: "publish-stylus", - contract_name: contractName, + contract_name: selectedContractName, cli_version: "", project_type: "stylus", }, @@ -178,12 +213,10 @@ async function buildStylus(spinner: Ora, secretKey?: string) { } } -function extractContractNameFromExportAbi(abiRawOutput: string): string | null { - const match = abiRawOutput.match(/:(I[A-Za-z0-9_]+)/); - if (match?.[1]) { - return match[1].replace(/^I/, ""); - } - return null; +function extractContractNamesFromExportAbi(abiRawOutput: string): string[] { + return [...abiRawOutput.matchAll(/:(I?[A-Za-z0-9_]+)/g)] + .map((m) => m[1]) + .filter((name): name is string => typeof name === "string"); } function getUrl(hash: string, command: string) { diff --git a/packages/thirdweb/src/cli/commands/stylus/create.ts b/packages/thirdweb/src/cli/commands/stylus/create.ts index 561517067b1..d632fd06010 100644 --- a/packages/thirdweb/src/cli/commands/stylus/create.ts +++ b/packages/thirdweb/src/cli/commands/stylus/create.ts @@ -37,15 +37,40 @@ export async function createStylusProject() { message: "Project name:", initial: "my-stylus-project", }); - spinner.start(`Creating new Stylus project: ${projectName}...`); - const newProject = spawnSync("cargo", ["stylus", "new", projectName], { - stdio: "inherit", + + // Step 4: Select project type + const { projectType } = await prompts({ + type: "select", + name: "projectType", + message: "Select a template:", + choices: [ + { title: "Default", value: "default" }, + { title: "ERC20", value: "erc20" }, + ], }); - if (newProject.status !== 0) { - spinner.fail("Failed to create Stylus project."); - process.exit(1); + + // Step 5: Create the project + if (projectType === "default") { + spinner.start(`Creating new Stylus project: ${projectName}...`); + const newProject = spawnSync("cargo", ["stylus", "new", projectName], { + stdio: "inherit", + }); + if (newProject.status !== 0) { + spinner.fail("Failed to create Stylus project."); + process.exit(1); + } + } else if (projectType === "erc20") { + const repoUrl = "git@github.com:thirdweb-example/stylus-erc20-template.git"; + spinner.start(`Creating new ERC20 Stylus project: ${projectName}...`); + const clone = spawnSync("git", ["clone", repoUrl, projectName], { + stdio: "inherit", + }); + if (clone.status !== 0) { + spinner.fail("Failed to create Stylus project."); + process.exit(1); + } } - spinner.succeed("Project created successfully."); - console.log(`\n✅ Done! cd into your project: ${projectName}`); + spinner.succeed("Project created successfully."); + console.log(`\n✅ cd into your project: ${projectName}`); }