diff --git a/contributors/DEVELOPER-GUIDE.md b/contributors/DEVELOPER-GUIDE.md index 62e37946d..0a92a1aec 100644 --- a/contributors/DEVELOPER-GUIDE.md +++ b/contributors/DEVELOPER-GUIDE.md @@ -23,13 +23,13 @@ yarn cli This command will run the compiled script inside `bin/`. -You can send any option or flag to the CLI command. For example, a handy command is `yarn cli -s` to tell the CLI to skip installing dependencies or `yarn cli [project_path]` example `yarn cli ../test-cli` this will skip the "Project Name" prompt and use the provided path where project instance will be created in. +You can send any option or flag to the CLI command. For example, a handy command is `yarn cli --skip` to tell the CLI to skip installing dependencies or `yarn cli [project_path]` example `yarn cli ../test-cli` this will skip the "Project Name" prompt and use the provided path where project instance will be created in. ## Changes to the Resulting Project -The source files for the instance projects can be found under `templates/`. You'll see there are two folders there: `base/` and `extensions/`. The `base/` folder has the source files that will be present in all instances, whereas `extensions/` hold the source files that will be added or not to the instances based on the user choices within the CLI tool. +The source files for the instance projects can be found under `templates/`. You'll see there are two folders there: `base/` and `solidity-frameworks/`. The `base/` folder has the source files that will be present in all instances, whereas `solidity-frameworks/` hold the source files that will be added or not to the instances based on the user choices within the CLI tool. -It's highly recommended that you go through [core-extensions.md](core-extensions.md) to understand the template API to create extensions. We use a custom template API to allow extensions to modify any file inside the `templates/` folder. While flexible and powerful, it requires developers to understand how it works. It's JS based, so there's no new technology needed to understand and use it. +It's highly recommended that you go through [TEMPLATING.md](TEMPLATING.md) to understand the template API to create extensions. We use a custom template API to allow extensions to modify any file inside the `templates/` folder. While flexible and powerful, it requires developers to understand how it works. It's JS based, so there's no new technology needed to understand and use it. While you might be tempted to change files straight in the source, we've created a better way to do it with the dev mode. We feel this is worth a separate section in this document. diff --git a/contributors/core-extensions.md b/contributors/TEMPLATING.md similarity index 81% rename from contributors/core-extensions.md rename to contributors/TEMPLATING.md index 8f424cda3..8b073520f 100644 --- a/contributors/core-extensions.md +++ b/contributors/TEMPLATING.md @@ -1,42 +1,3 @@ -# Main concepts - -I propose we treat anything other than "base" as an extension. That way we don't need to make distinctions between solidity frameworks or any other kind of extension. - -This change should make it easier to grow the options we provide our users without having to classify extensions by category. - -This change requires a new file, `src/config.ts`, where a few things about the extensions are defined, e.g. the sequence of questions about extensions. - -# Config files - -There's one main `src/config.ts` file to configure the questions shown to the user. - -For each extension there is an optional `templates/extensions/{extensionName}/config.json` file providing information about the specific extension. - -| ⚠️ Note how the extension config file is a JSON file - -## Config files API - -### `src/config.ts` - -Have a look at `src/types.ts#Config` or the file itself. - -Just a quick note to mention that adding `null` as an item in the `extensions` property will show the "None" option to the user. That option doesn't add any extension for the given question. - -### `{extension}/config.json` - -Since these files can't be .ts, the API is not typed. However, there are certain properties that are used in the code. - -Those properties are: - -- `name`: the string to be used when showing the package name to the user via the cli, as well as for error reporting. - -Note that all values are optional, as well as the file itself. - -| ⚠️ TODO list when new properties are added to config.json: -| - Update this document -| - Update the ExtensionDescriptor type at /src/types.ts -| - Update the src/utils/extensions-dictionary.ts file so the new field from the config is actually added into the extension descriptor - # Template files A Template file is a file to which extensions can add content. Removing content is out of scope for this experiment. @@ -191,8 +152,6 @@ I've thought about how the strings should be joined, but an option is to use [ta # Extension folder anatomy -When creating a new extension, simply create a new folder under `templates/extensions` with the name you want the extension to have. - Inside the folder you will have a mix of normal, templated, and special files and folders. ## Normal files and folders @@ -211,8 +170,7 @@ Templated files are both [Template files](#template-files), and [Args files](#ar The special files and folders are: - [`package.json` file](#merging-packagejson-files) -- [`config.json` file](#extensionconfigjson) -- `extensions/` folder +- `solidity-frameworks/` folder # Things worth mentioning diff --git a/src/cli.ts b/src/cli.ts index 324e41ff4..6a2528bcd 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -18,7 +18,7 @@ export async function cli(args: Args) { } const options = await promptForMissingOptions(rawOptions); - if (options.extensions.includes(SOLIDITY_FRAMEWORKS.FOUNDRY)) { + if (options.solidityFramework === SOLIDITY_FRAMEWORKS.FOUNDRY) { await validateFoundryUp(); } diff --git a/src/config.ts b/src/config.ts deleted file mode 100644 index 283c48edd..000000000 --- a/src/config.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Config, ExternalExtension, typedQuestion } from "./types"; -import { SOLIDITY_FRAMEWORKS } from "./utils/consts"; - -const config: Config = { - questions: [ - typedQuestion({ - type: "single-select", - name: "solidityFramework", - message: "What solidity framework do you want to use?", - extensions: [SOLIDITY_FRAMEWORKS.HARDHAT, SOLIDITY_FRAMEWORKS.FOUNDRY, null], - default: SOLIDITY_FRAMEWORKS.HARDHAT, - }), - ], -}; - -const CURATED_EXTENSIONS: { [key: string]: ExternalExtension } = { - subgraph: { - repository: "https://github.com/scaffold-eth/create-eth-extensions", - branch: "subgraph", - }, - "eip-712": { - repository: "https://github.com/scaffold-eth/create-eth-extensions", - branch: "eip-712", - }, -}; - -export { config, CURATED_EXTENSIONS }; diff --git a/src/curated-extensions.ts b/src/curated-extensions.ts new file mode 100644 index 000000000..bf7089493 --- /dev/null +++ b/src/curated-extensions.ts @@ -0,0 +1,14 @@ +import { ExternalExtension } from "./types"; + +const CURATED_EXTENSIONS: { [key: string]: ExternalExtension } = { + subgraph: { + repository: "https://github.com/scaffold-eth/create-eth-extensions", + branch: "subgraph", + }, + "eip-712": { + repository: "https://github.com/scaffold-eth/create-eth-extensions", + branch: "eip-712", + }, +}; + +export { CURATED_EXTENSIONS }; diff --git a/src/main.ts b/src/main.ts index 7dfdb0fae..b506c4ec3 100644 --- a/src/main.ts +++ b/src/main.ts @@ -50,7 +50,7 @@ export async function createProject(options: Options) { }, }, { - title: `📡 Initializing Git repository${options.extensions.includes(SOLIDITY_FRAMEWORKS.FOUNDRY) ? " and submodules" : ""}`, + title: `📡 Initializing Git repository${options.solidityFramework === SOLIDITY_FRAMEWORKS.FOUNDRY ? " and submodules" : ""}`, task: () => createFirstGitCommit(targetDirectory, options), }, ], diff --git a/src/tasks/copy-template-files.ts b/src/tasks/copy-template-files.ts index f13fa1fd7..ac17c3d78 100644 --- a/src/tasks/copy-template-files.ts +++ b/src/tasks/copy-template-files.ts @@ -1,18 +1,19 @@ import { execa } from "execa"; -import { ExternalExtension, Options, TemplateDescriptor } from "../types"; -import { baseDir } from "../utils/consts"; -import { extensionDict } from "../utils/extensions-dictionary"; +import { ExternalExtension, Options, SolidityFramework, TemplateDescriptor } from "../types"; import { findFilesRecursiveSync } from "../utils/find-files-recursively"; import { mergePackageJson } from "../utils/merge-package-json"; import fs from "fs"; -import url from "url"; +import { pathToFileURL } from "url"; import ncp from "ncp"; import path from "path"; import { promisify } from "util"; import link from "../utils/link"; import { getArgumentFromExternalExtensionOption } from "../utils/external-extensions"; -const EXTERNAL_EXTENSION_TMP_FOLDER = "tmp-external-extension"; +const BASE_DIR = "base"; +const EXTERNAL_EXTENSION_TMP_DIR = "tmp-external-extension"; +const SOLIDITY_FRAMEWORKS_DIR = "solidity-frameworks"; + const copy = promisify(ncp); let copyOrLink = copy; @@ -21,10 +22,13 @@ const isPackageJsonRegex = /package\.json/; const isYarnLockRegex = /yarn\.lock/; const isConfigRegex = /([^/\\]*?)\\config\.json/; const isArgsRegex = /([^/\\]*?)\.args\./; -const isExtensionFolderRegex = /extensions$/; +const isSolidityFrameworkFolderRegex = /solidity-frameworks$/; const isPackagesFolderRegex = /packages$/; const isDeployedContractsRegex = /packages\/nextjs\/contracts\/deployedContracts\.ts/; +const getSolidityFrameworkPath = (solidityFramework: SolidityFramework, templatesDirectory: string) => + path.resolve(templatesDirectory, SOLIDITY_FRAMEWORKS_DIR, solidityFramework); + const copyBaseFiles = async (basePath: string, targetDir: string, { dev: isDev }: Options) => { await copyOrLink(basePath, targetDir, { clobber: false, @@ -69,12 +73,13 @@ const copyExtensionsFiles = async ({ dev: isDev }: Options, extensionPath: strin filter: path => { const isConfig = isConfigRegex.test(path); const isArgs = isArgsRegex.test(path); - const isExtensionFolder = isExtensionFolderRegex.test(path) && fs.lstatSync(path).isDirectory(); + const isSolidityFrameworkFolder = isSolidityFrameworkFolderRegex.test(path) && fs.lstatSync(path).isDirectory(); const isPackagesFolder = isPackagesFolderRegex.test(path) && fs.lstatSync(path).isDirectory(); const isTemplate = isTemplateRegex.test(path); // PR NOTE: this wasn't needed before because ncp had the clobber: false const isPackageJson = isPackageJsonRegex.test(path); - const shouldSkip = isConfig || isArgs || isTemplate || isPackageJson || isExtensionFolder || isPackagesFolder; + const shouldSkip = + isConfig || isArgs || isTemplate || isPackageJson || isSolidityFrameworkFolder || isPackagesFolder; return !shouldSkip; }, }); @@ -111,40 +116,39 @@ const copyExtensionsFiles = async ({ dev: isDev }: Options, extensionPath: strin }; const processTemplatedFiles = async ( - { extensions, externalExtension, dev: isDev }: Options, + { solidityFramework, externalExtension, dev: isDev }: Options, basePath: string, + solidityFrameworkPath: string | null, targetDir: string, ) => { const baseTemplatedFileDescriptors: TemplateDescriptor[] = findFilesRecursiveSync(basePath, path => isTemplateRegex.test(path), ).map(baseTemplatePath => ({ path: baseTemplatePath, - fileUrl: url.pathToFileURL(baseTemplatePath).href, + fileUrl: pathToFileURL(baseTemplatePath).href, relativePath: baseTemplatePath.split(basePath)[1], source: "base", })); - const extensionsTemplatedFileDescriptors: TemplateDescriptor[] = extensions - .map(ext => - findFilesRecursiveSync(extensionDict[ext].path, filePath => isTemplateRegex.test(filePath)).map( - extensionTemplatePath => ({ - path: extensionTemplatePath, - fileUrl: url.pathToFileURL(extensionTemplatePath).href, - relativePath: extensionTemplatePath.split(extensionDict[ext].path)[1], - source: `extension ${extensionDict[ext].name}`, - }), - ), - ) - .flat(); + const solidityFrameworkTemplatedFileDescriptors: TemplateDescriptor[] = solidityFrameworkPath + ? findFilesRecursiveSync(solidityFrameworkPath, filePath => isTemplateRegex.test(filePath)) + .map(solidityFrameworkTemplatePath => ({ + path: solidityFrameworkTemplatePath, + fileUrl: pathToFileURL(solidityFrameworkTemplatePath).href, + relativePath: solidityFrameworkTemplatePath.split(solidityFrameworkPath)[1], + source: `extension ${solidityFramework}`, + })) + .flat() + : []; const externalExtensionFolder = isDev ? path.join(basePath, "../../externalExtensions", externalExtension as string, "extension") - : path.join(targetDir, EXTERNAL_EXTENSION_TMP_FOLDER, "extension"); + : path.join(targetDir, EXTERNAL_EXTENSION_TMP_DIR, "extension"); const externalExtensionTemplatedFileDescriptors: TemplateDescriptor[] = externalExtension ? findFilesRecursiveSync(externalExtensionFolder, filePath => isTemplateRegex.test(filePath)).map( extensionTemplatePath => ({ path: extensionTemplatePath, - fileUrl: url.pathToFileURL(extensionTemplatePath).href, + fileUrl: pathToFileURL(extensionTemplatePath).href, relativePath: extensionTemplatePath.split(externalExtensionFolder)[1], source: `external extension ${isDev ? (externalExtension as string) : getArgumentFromExternalExtensionOption(externalExtension)}`, }), @@ -154,32 +158,31 @@ const processTemplatedFiles = async ( await Promise.all( [ ...baseTemplatedFileDescriptors, - ...extensionsTemplatedFileDescriptors, + ...solidityFrameworkTemplatedFileDescriptors, ...externalExtensionTemplatedFileDescriptors, ].map(async templateFileDescriptor => { const templateTargetName = templateFileDescriptor.path.match(isTemplateRegex)?.[1] as string; const argsPath = templateFileDescriptor.relativePath.replace(isTemplateRegex, `${templateTargetName}.args.`); - const argsFileUrls = extensions - .map(extension => { - const argsFilePath = path.join(extensionDict[extension].path, argsPath); - const fileExists = fs.existsSync(argsFilePath); - if (!fileExists) { - return []; - } - return url.pathToFileURL(argsFilePath).href; - }) - .flat(); + const argsFileUrls = []; + + if (solidityFrameworkPath) { + const argsFilePath = path.join(solidityFrameworkPath, argsPath); + const fileExists = fs.existsSync(argsFilePath); + if (fileExists) { + argsFileUrls.push(pathToFileURL(argsFilePath).href); + } + } if (externalExtension) { const argsFilePath = isDev ? path.join(basePath, "../../externalExtensions", externalExtension as string, "extension", argsPath) - : path.join(targetDir, EXTERNAL_EXTENSION_TMP_FOLDER, "extension", argsPath); + : path.join(targetDir, EXTERNAL_EXTENSION_TMP_DIR, "extension", argsPath); const fileExists = fs.existsSync(argsFilePath); if (fileExists) { - argsFileUrls?.push(url.pathToFileURL(argsFilePath).href); + argsFileUrls?.push(pathToFileURL(argsFilePath).href); } } @@ -276,19 +279,19 @@ const setUpExternalExtensionFiles = async (options: Options, tmpDir: string) => export async function copyTemplateFiles(options: Options, templateDir: string, targetDir: string) { copyOrLink = options.dev ? link : copy; - const basePath = path.join(templateDir, baseDir); - const tmpDir = path.join(targetDir, EXTERNAL_EXTENSION_TMP_FOLDER); + const basePath = path.join(templateDir, BASE_DIR); + const tmpDir = path.join(targetDir, EXTERNAL_EXTENSION_TMP_DIR); // 1. Copy base template to target directory await copyBaseFiles(basePath, targetDir, options); - // 2. Copy extensions folders - await Promise.all( - options.extensions.map(async extension => { - const extensionPath = extensionDict[extension].path; - await copyExtensionsFiles(options, extensionPath, targetDir); - }), - ); + // 2. Copy solidity framework folder + const solidityFrameworkPath = + options.solidityFramework && getSolidityFrameworkPath(options.solidityFramework, templateDir); + + if (solidityFrameworkPath) { + await copyExtensionsFiles(options, solidityFrameworkPath, targetDir); + } // 3. Set up external extension if needed if (options.externalExtension) { @@ -308,7 +311,7 @@ export async function copyTemplateFiles(options: Options, templateDir: string, t } // 4. Process templated files and generate output - await processTemplatedFiles(options, basePath, targetDir); + await processTemplatedFiles(options, basePath, solidityFrameworkPath, targetDir); // 5. Delete tmp directory if (options.externalExtension && !options.dev) { diff --git a/src/tasks/create-first-git-commit.ts b/src/tasks/create-first-git-commit.ts index 9565ae194..68e059fb0 100644 --- a/src/tasks/create-first-git-commit.ts +++ b/src/tasks/create-first-git-commit.ts @@ -10,7 +10,7 @@ export async function createFirstGitCommit(targetDir: string, options: Options) await execa("git", ["add", "-A"], { cwd: targetDir }); await execa("git", ["commit", "-m", "Initial commit with 🏗️ Scaffold-ETH 2", "--no-verify"], { cwd: targetDir }); - if (options.extensions.includes(SOLIDITY_FRAMEWORKS.FOUNDRY)) { + if (options.solidityFramework === SOLIDITY_FRAMEWORKS.FOUNDRY) { const foundryWorkSpacePath = path.resolve(targetDir, "packages", SOLIDITY_FRAMEWORKS.FOUNDRY); // forge install foundry libraries await execa("forge", ["install", ...foundryLibraries], { cwd: foundryWorkSpacePath }); diff --git a/src/tasks/prettier-format.ts b/src/tasks/prettier-format.ts index 58e5458d2..221625189 100644 --- a/src/tasks/prettier-format.ts +++ b/src/tasks/prettier-format.ts @@ -25,7 +25,7 @@ export async function prettierFormat(targetDir: string, options: Options) { await runPrettier([nextJsPath], nextPrettierConfig, ["--plugin=@trivago/prettier-plugin-sort-imports"]); - if (options.extensions.includes(SOLIDITY_FRAMEWORKS.HARDHAT)) { + if (options.solidityFramework === SOLIDITY_FRAMEWORKS.HARDHAT) { const hardhatPackagePath = path.join(targetDir, "packages", SOLIDITY_FRAMEWORKS.HARDHAT); const hardhatPrettierConfig = path.join(hardhatPackagePath, ".prettierrc.json"); const hardhatPaths = [ @@ -39,7 +39,7 @@ export async function prettierFormat(targetDir: string, options: Options) { await runPrettier(hardhatPaths, hardhatPrettierConfig, ["--plugin=prettier-plugin-solidity"]); } - if (options.extensions.includes(SOLIDITY_FRAMEWORKS.FOUNDRY)) { + if (options.solidityFramework === SOLIDITY_FRAMEWORKS.FOUNDRY) { const foundryPackagePath = path.resolve(targetDir, "packages", SOLIDITY_FRAMEWORKS.FOUNDRY); const foundryResult = await execa("forge", ["fmt"], { cwd: foundryPackagePath }); if (foundryResult.failed) { diff --git a/src/types.ts b/src/types.ts index 7e563957d..2b75ac149 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,82 +1,29 @@ -import type { Question } from "inquirer"; - export type Args = string[]; +export type SolidityFramework = "hardhat" | "foundry"; +export type ExternalExtensionNameDev = string; + +export type ExternalExtension = { + repository: string; + branch?: string | null; +}; type BaseOptions = { project: string | null; install: boolean | null; dev: boolean; externalExtension: ExternalExtension | ExternalExtensionNameDev | null; + solidityFramework: SolidityFramework | "none" | null; }; -export type ExternalExtension = { - repository: string; - branch?: string | null; -}; - -export type ExternalExtensionNameDev = string; - export type RawOptions = BaseOptions & { - solidityFramework: SolidityFramework | "none" | null; help: boolean; }; -type MergedOptions = BaseOptions & { - extensions: Extension[]; -}; - -type NonNullableMergedOptions = { - [Prop in keyof Omit]: NonNullable; +export type Options = { + [Prop in keyof Omit]: NonNullable; } & { externalExtension: RawOptions["externalExtension"]; -}; - -export type Options = NonNullableMergedOptions; - -export type SolidityFramework = "hardhat" | "foundry"; - -export type Extension = SolidityFramework; - -type NullExtension = null; -export type ExtensionOrNull = Extension | NullExtension; -// corresponds to inquirer question types: -// - multi-select -> checkbox -// - single-select -> list -type QuestionType = "multi-select" | "single-select"; -interface ExtensionQuestion { - type: QuestionType; - extensions: T; - name: string; - message: Question["message"]; - default?: T[number]; -} - -export const isExtension = (item: ExtensionOrNull): item is Extension => item !== null; - -/** - * This function makes sure that the `T` generic type is narrowed down to - * whatever `extensions` are passed in the question prop. That way we can type - * check the `default` prop is not using any valid extension, but only one - * already provided in the `extensions` prop. - * - * Questions can be created without this function, just using a normal object, - * but `default` type will be any valid Extension. - */ -export const typedQuestion = (question: ExtensionQuestion) => question; -export type Config = { - questions: ExtensionQuestion[]; -}; - -export const isDefined = (item: T | undefined | null): item is T => item !== undefined && item !== null; - -export type ExtensionDescriptor = { - name: string; - value: Extension; - path: string; -}; - -export type ExtensionDict = { - [extension in Extension]: ExtensionDescriptor; + solidityFramework: SolidityFramework | null; }; export type TemplateDescriptor = { diff --git a/src/utils/consts.ts b/src/utils/consts.ts index af21b61a9..70e4bcb71 100644 --- a/src/utils/consts.ts +++ b/src/utils/consts.ts @@ -1,5 +1,3 @@ -export const baseDir = "base"; - export const SOLIDITY_FRAMEWORKS = { HARDHAT: "hardhat", FOUNDRY: "foundry", diff --git a/src/utils/extensions-dictionary.ts b/src/utils/extensions-dictionary.ts deleted file mode 100644 index b7862e410..000000000 --- a/src/utils/extensions-dictionary.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { fileURLToPath } from "url"; -import path from "path"; -import fs from "fs"; -import { Extension, ExtensionDescriptor, ExtensionDict } from "../types"; - -// global object to store mapping of extension name and its descriptor -export const extensionDict: ExtensionDict = {} as ExtensionDict; - -const currentFileUrl = import.meta.url; - -const templatesDirectory = path.resolve(decodeURI(fileURLToPath(currentFileUrl)), "../../templates"); - -/** - * This function has side effects. It initializes the extensionDict. - */ -const initializeExtensionsDict = (basePath: string) => { - const extensionsPath = path.resolve(basePath, "extensions"); - let extensions: Extension[]; - try { - extensions = fs.readdirSync(extensionsPath) as Extension[]; - } catch (error) { - console.error(`Couldn't read the extensions directory: ${extensionsPath}`); - return; - } - - extensions.forEach(ext => { - const extPath = path.resolve(extensionsPath, ext); - const configPath = path.resolve(extPath, "config.json"); - - let config: Record = {}; - try { - config = JSON.parse(fs.readFileSync(configPath, "utf8")) as Record; - } catch (error) { - if (fs.existsSync(configPath)) { - throw new Error( - `Couldn't parse existing config.json file. -Extension: ${ext}; -Config file path: ${configPath}`, - ); - } - } - const name = config.name ?? ext; - const value = ext; - - const extDescriptor: ExtensionDescriptor = { - name, - value, - path: extPath, - }; - - extensionDict[ext] = extDescriptor; - }); -}; - -// This function call will run only once due to Node.js module caching in first import of file -// it won't run again even if imported in multiple files. -initializeExtensionsDict(templatesDirectory); diff --git a/src/utils/external-extensions.ts b/src/utils/external-extensions.ts index 5adf8a058..3cda04355 100644 --- a/src/utils/external-extensions.ts +++ b/src/utils/external-extensions.ts @@ -1,5 +1,5 @@ import { ExternalExtension, RawOptions } from "../types"; -import { CURATED_EXTENSIONS } from "../config"; +import { CURATED_EXTENSIONS } from "../curated-extensions"; // Gets the data from the argument passed to the `--extension` option. // e.g. owner/project:branch => { githubBranchUrl, githubUrl, branch, owner, project } diff --git a/src/utils/parse-arguments-into-options.ts b/src/utils/parse-arguments-into-options.ts index eb711125b..0a6f9ec7f 100644 --- a/src/utils/parse-arguments-into-options.ts +++ b/src/utils/parse-arguments-into-options.ts @@ -3,7 +3,7 @@ import arg from "arg"; import * as https from "https"; import { getDataFromExternalExtensionArgument } from "./external-extensions"; import chalk from "chalk"; -import { CURATED_EXTENSIONS } from "../config"; +import { CURATED_EXTENSIONS } from "../curated-extensions"; import { SOLIDITY_FRAMEWORKS } from "./consts"; import { validateFoundryUp } from "./system-validation"; import fs from "fs"; diff --git a/src/utils/prompt-for-missing-options.ts b/src/utils/prompt-for-missing-options.ts index 0532d9b8c..bb5a89ce9 100644 --- a/src/utils/prompt-for-missing-options.ts +++ b/src/utils/prompt-for-missing-options.ts @@ -1,19 +1,17 @@ -import { config } from "../config"; -import { Options, RawOptions, isDefined, isExtension } from "../types"; +import { Options, RawOptions } from "../types"; import inquirer from "inquirer"; -import { extensionDict } from "./extensions-dictionary"; +import { SOLIDITY_FRAMEWORKS } from "./consts"; // default values for unspecified args const defaultOptions: RawOptions = { project: "my-dapp-example", + solidityFramework: null, install: true, dev: false, externalExtension: null, help: false, - solidityFramework: null, }; -const invalidQuestionNames = ["project", "install"]; const nullExtensionChoice = { name: "none", value: null, @@ -21,46 +19,28 @@ const nullExtensionChoice = { export async function promptForMissingOptions(options: RawOptions): Promise { const cliAnswers = Object.fromEntries(Object.entries(options).filter(([, value]) => value !== null)); - const questions = []; - - questions.push({ - type: "input", - name: "project", - message: "Your project name:", - default: defaultOptions.project, - validate: (value: string) => value.length > 0, - }); - - config.questions.forEach(question => { - if (invalidQuestionNames.includes(question.name)) { - throw new Error( - `The name of the question can't be "${question.name}". The invalid names are: ${invalidQuestionNames - .map(w => `"${w}"`) - .join(", ")}`, - ); - } - - const extensions = question.extensions - .filter(isExtension) - .map(ext => extensionDict[ext]) - .filter(isDefined); - - const hasNoneOption = question.extensions.includes(null); - - questions.push({ - type: question.type === "multi-select" ? "checkbox" : "list", - name: question.name, - message: question.message, - choices: hasNoneOption ? [...extensions, nullExtensionChoice] : extensions, - }); - }); - - questions.push({ - type: "confirm", - name: "install", - message: "Install packages?", - default: defaultOptions.install, - }); + const questions = [ + { + type: "input", + name: "project", + message: "Your project name:", + default: defaultOptions.project, + validate: (value: string) => value.length > 0, + }, + { + type: "list", + name: "solidityFramework", + message: "What solidity framework do you want to use?", + choices: [SOLIDITY_FRAMEWORKS.HARDHAT, SOLIDITY_FRAMEWORKS.FOUNDRY, nullExtensionChoice], + default: SOLIDITY_FRAMEWORKS.HARDHAT, + }, + { + type: "confirm", + name: "install", + message: "Install packages?", + default: defaultOptions.install, + }, + ]; const answers = await inquirer.prompt(questions, cliAnswers); @@ -68,7 +48,7 @@ export async function promptForMissingOptions(options: RawOptions): Promise Boolean(ext) && ext !== "none"), + solidityFramework: options.solidityFramework ?? answers.solidityFramework, externalExtension: options.externalExtension, }; diff --git a/src/utils/render-outro-message.ts b/src/utils/render-outro-message.ts index b905c61fd..4bb10d904 100644 --- a/src/utils/render-outro-message.ts +++ b/src/utils/render-outro-message.ts @@ -13,8 +13,8 @@ export function renderOutroMessage(options: Options) { `; if ( - options.extensions.includes(SOLIDITY_FRAMEWORKS.HARDHAT) || - options.extensions.includes(SOLIDITY_FRAMEWORKS.FOUNDRY) + options.solidityFramework === SOLIDITY_FRAMEWORKS.HARDHAT || + options.solidityFramework === SOLIDITY_FRAMEWORKS.FOUNDRY ) { message += ` \t${chalk.bold("Start the local development node")} diff --git a/templates/extensions/foundry/.github/workflows/lint.yaml.args.mjs b/templates/solidity-frameworks/foundry/.github/workflows/lint.yaml.args.mjs similarity index 100% rename from templates/extensions/foundry/.github/workflows/lint.yaml.args.mjs rename to templates/solidity-frameworks/foundry/.github/workflows/lint.yaml.args.mjs diff --git a/templates/extensions/foundry/README.md.args.mjs b/templates/solidity-frameworks/foundry/README.md.args.mjs similarity index 100% rename from templates/extensions/foundry/README.md.args.mjs rename to templates/solidity-frameworks/foundry/README.md.args.mjs diff --git a/templates/extensions/foundry/package.json b/templates/solidity-frameworks/foundry/package.json similarity index 100% rename from templates/extensions/foundry/package.json rename to templates/solidity-frameworks/foundry/package.json diff --git a/templates/extensions/foundry/packages/foundry/.env.example b/templates/solidity-frameworks/foundry/packages/foundry/.env.example similarity index 100% rename from templates/extensions/foundry/packages/foundry/.env.example rename to templates/solidity-frameworks/foundry/packages/foundry/.env.example diff --git a/templates/extensions/foundry/packages/foundry/.env.template.mjs b/templates/solidity-frameworks/foundry/packages/foundry/.env.template.mjs similarity index 100% rename from templates/extensions/foundry/packages/foundry/.env.template.mjs rename to templates/solidity-frameworks/foundry/packages/foundry/.env.template.mjs diff --git a/templates/extensions/foundry/packages/foundry/.gitignore.template.mjs b/templates/solidity-frameworks/foundry/packages/foundry/.gitignore.template.mjs similarity index 100% rename from templates/extensions/foundry/packages/foundry/.gitignore.template.mjs rename to templates/solidity-frameworks/foundry/packages/foundry/.gitignore.template.mjs diff --git a/templates/extensions/foundry/packages/foundry/.prettier.json b/templates/solidity-frameworks/foundry/packages/foundry/.prettier.json similarity index 100% rename from templates/extensions/foundry/packages/foundry/.prettier.json rename to templates/solidity-frameworks/foundry/packages/foundry/.prettier.json diff --git a/templates/extensions/foundry/packages/foundry/contracts/YourContract.sol b/templates/solidity-frameworks/foundry/packages/foundry/contracts/YourContract.sol similarity index 100% rename from templates/extensions/foundry/packages/foundry/contracts/YourContract.sol rename to templates/solidity-frameworks/foundry/packages/foundry/contracts/YourContract.sol diff --git a/templates/extensions/foundry/packages/foundry/deployments/.gitignore.template.mjs b/templates/solidity-frameworks/foundry/packages/foundry/deployments/.gitignore.template.mjs similarity index 100% rename from templates/extensions/foundry/packages/foundry/deployments/.gitignore.template.mjs rename to templates/solidity-frameworks/foundry/packages/foundry/deployments/.gitignore.template.mjs diff --git a/templates/extensions/foundry/packages/foundry/foundry.toml b/templates/solidity-frameworks/foundry/packages/foundry/foundry.toml similarity index 100% rename from templates/extensions/foundry/packages/foundry/foundry.toml rename to templates/solidity-frameworks/foundry/packages/foundry/foundry.toml diff --git a/templates/extensions/foundry/packages/foundry/package.json b/templates/solidity-frameworks/foundry/packages/foundry/package.json similarity index 100% rename from templates/extensions/foundry/packages/foundry/package.json rename to templates/solidity-frameworks/foundry/packages/foundry/package.json diff --git a/templates/extensions/foundry/packages/foundry/remappings.txt b/templates/solidity-frameworks/foundry/packages/foundry/remappings.txt similarity index 100% rename from templates/extensions/foundry/packages/foundry/remappings.txt rename to templates/solidity-frameworks/foundry/packages/foundry/remappings.txt diff --git a/templates/extensions/foundry/packages/foundry/script/Deploy.s.sol.template.mjs b/templates/solidity-frameworks/foundry/packages/foundry/script/Deploy.s.sol.template.mjs similarity index 100% rename from templates/extensions/foundry/packages/foundry/script/Deploy.s.sol.template.mjs rename to templates/solidity-frameworks/foundry/packages/foundry/script/Deploy.s.sol.template.mjs diff --git a/templates/extensions/foundry/packages/foundry/script/DeployHelpers.s.sol b/templates/solidity-frameworks/foundry/packages/foundry/script/DeployHelpers.s.sol similarity index 100% rename from templates/extensions/foundry/packages/foundry/script/DeployHelpers.s.sol rename to templates/solidity-frameworks/foundry/packages/foundry/script/DeployHelpers.s.sol diff --git a/templates/extensions/foundry/packages/foundry/script/ListAccount.js b/templates/solidity-frameworks/foundry/packages/foundry/script/ListAccount.js similarity index 100% rename from templates/extensions/foundry/packages/foundry/script/ListAccount.js rename to templates/solidity-frameworks/foundry/packages/foundry/script/ListAccount.js diff --git a/templates/extensions/foundry/packages/foundry/script/VerifyAll.s.sol b/templates/solidity-frameworks/foundry/packages/foundry/script/VerifyAll.s.sol similarity index 100% rename from templates/extensions/foundry/packages/foundry/script/VerifyAll.s.sol rename to templates/solidity-frameworks/foundry/packages/foundry/script/VerifyAll.s.sol diff --git a/templates/extensions/foundry/packages/foundry/script/generateAccount.js b/templates/solidity-frameworks/foundry/packages/foundry/script/generateAccount.js similarity index 100% rename from templates/extensions/foundry/packages/foundry/script/generateAccount.js rename to templates/solidity-frameworks/foundry/packages/foundry/script/generateAccount.js diff --git a/templates/extensions/foundry/packages/foundry/script/generateTsAbis.js b/templates/solidity-frameworks/foundry/packages/foundry/script/generateTsAbis.js similarity index 100% rename from templates/extensions/foundry/packages/foundry/script/generateTsAbis.js rename to templates/solidity-frameworks/foundry/packages/foundry/script/generateTsAbis.js diff --git a/templates/extensions/foundry/packages/foundry/test/YourContract.t.sol b/templates/solidity-frameworks/foundry/packages/foundry/test/YourContract.t.sol similarity index 100% rename from templates/extensions/foundry/packages/foundry/test/YourContract.t.sol rename to templates/solidity-frameworks/foundry/packages/foundry/test/YourContract.t.sol diff --git a/templates/extensions/foundry/packages/nextjs/app/blockexplorer/address/[address]/page.tsx.args.mjs b/templates/solidity-frameworks/foundry/packages/nextjs/app/blockexplorer/address/[address]/page.tsx.args.mjs similarity index 100% rename from templates/extensions/foundry/packages/nextjs/app/blockexplorer/address/[address]/page.tsx.args.mjs rename to templates/solidity-frameworks/foundry/packages/nextjs/app/blockexplorer/address/[address]/page.tsx.args.mjs diff --git a/templates/extensions/foundry/packages/nextjs/scaffold.config.ts.args.mjs b/templates/solidity-frameworks/foundry/packages/nextjs/scaffold.config.ts.args.mjs similarity index 100% rename from templates/extensions/foundry/packages/nextjs/scaffold.config.ts.args.mjs rename to templates/solidity-frameworks/foundry/packages/nextjs/scaffold.config.ts.args.mjs diff --git a/templates/extensions/hardhat/.github/workflows/lint.yaml.args.mjs b/templates/solidity-frameworks/hardhat/.github/workflows/lint.yaml.args.mjs similarity index 100% rename from templates/extensions/hardhat/.github/workflows/lint.yaml.args.mjs rename to templates/solidity-frameworks/hardhat/.github/workflows/lint.yaml.args.mjs diff --git a/templates/extensions/hardhat/README.md.args.mjs b/templates/solidity-frameworks/hardhat/README.md.args.mjs similarity index 100% rename from templates/extensions/hardhat/README.md.args.mjs rename to templates/solidity-frameworks/hardhat/README.md.args.mjs diff --git a/templates/extensions/hardhat/package.json b/templates/solidity-frameworks/hardhat/package.json similarity index 100% rename from templates/extensions/hardhat/package.json rename to templates/solidity-frameworks/hardhat/package.json diff --git a/templates/extensions/hardhat/packages/hardhat/.env.example b/templates/solidity-frameworks/hardhat/packages/hardhat/.env.example similarity index 100% rename from templates/extensions/hardhat/packages/hardhat/.env.example rename to templates/solidity-frameworks/hardhat/packages/hardhat/.env.example diff --git a/templates/extensions/hardhat/packages/hardhat/.eslintignore b/templates/solidity-frameworks/hardhat/packages/hardhat/.eslintignore similarity index 100% rename from templates/extensions/hardhat/packages/hardhat/.eslintignore rename to templates/solidity-frameworks/hardhat/packages/hardhat/.eslintignore diff --git a/templates/extensions/hardhat/packages/hardhat/.eslintrc.json b/templates/solidity-frameworks/hardhat/packages/hardhat/.eslintrc.json similarity index 100% rename from templates/extensions/hardhat/packages/hardhat/.eslintrc.json rename to templates/solidity-frameworks/hardhat/packages/hardhat/.eslintrc.json diff --git a/templates/extensions/hardhat/packages/hardhat/.gitignore.template.mjs b/templates/solidity-frameworks/hardhat/packages/hardhat/.gitignore.template.mjs similarity index 100% rename from templates/extensions/hardhat/packages/hardhat/.gitignore.template.mjs rename to templates/solidity-frameworks/hardhat/packages/hardhat/.gitignore.template.mjs diff --git a/templates/extensions/hardhat/packages/hardhat/.prettierrc.json b/templates/solidity-frameworks/hardhat/packages/hardhat/.prettierrc.json similarity index 100% rename from templates/extensions/hardhat/packages/hardhat/.prettierrc.json rename to templates/solidity-frameworks/hardhat/packages/hardhat/.prettierrc.json diff --git a/templates/extensions/hardhat/packages/hardhat/contracts/YourContract.sol b/templates/solidity-frameworks/hardhat/packages/hardhat/contracts/YourContract.sol similarity index 100% rename from templates/extensions/hardhat/packages/hardhat/contracts/YourContract.sol rename to templates/solidity-frameworks/hardhat/packages/hardhat/contracts/YourContract.sol diff --git a/templates/extensions/hardhat/packages/hardhat/deploy/00_deploy_your_contract.ts b/templates/solidity-frameworks/hardhat/packages/hardhat/deploy/00_deploy_your_contract.ts similarity index 100% rename from templates/extensions/hardhat/packages/hardhat/deploy/00_deploy_your_contract.ts rename to templates/solidity-frameworks/hardhat/packages/hardhat/deploy/00_deploy_your_contract.ts diff --git a/templates/extensions/hardhat/packages/hardhat/deploy/99_generateTsAbis.ts b/templates/solidity-frameworks/hardhat/packages/hardhat/deploy/99_generateTsAbis.ts similarity index 100% rename from templates/extensions/hardhat/packages/hardhat/deploy/99_generateTsAbis.ts rename to templates/solidity-frameworks/hardhat/packages/hardhat/deploy/99_generateTsAbis.ts diff --git a/templates/extensions/hardhat/packages/hardhat/hardhat.config.ts b/templates/solidity-frameworks/hardhat/packages/hardhat/hardhat.config.ts similarity index 100% rename from templates/extensions/hardhat/packages/hardhat/hardhat.config.ts rename to templates/solidity-frameworks/hardhat/packages/hardhat/hardhat.config.ts diff --git a/templates/extensions/hardhat/packages/hardhat/package.json b/templates/solidity-frameworks/hardhat/packages/hardhat/package.json similarity index 100% rename from templates/extensions/hardhat/packages/hardhat/package.json rename to templates/solidity-frameworks/hardhat/packages/hardhat/package.json diff --git a/templates/extensions/hardhat/packages/hardhat/scripts/generateAccount.ts b/templates/solidity-frameworks/hardhat/packages/hardhat/scripts/generateAccount.ts similarity index 100% rename from templates/extensions/hardhat/packages/hardhat/scripts/generateAccount.ts rename to templates/solidity-frameworks/hardhat/packages/hardhat/scripts/generateAccount.ts diff --git a/templates/extensions/hardhat/packages/hardhat/scripts/listAccount.ts b/templates/solidity-frameworks/hardhat/packages/hardhat/scripts/listAccount.ts similarity index 100% rename from templates/extensions/hardhat/packages/hardhat/scripts/listAccount.ts rename to templates/solidity-frameworks/hardhat/packages/hardhat/scripts/listAccount.ts diff --git a/templates/extensions/hardhat/packages/hardhat/test/YourContract.ts b/templates/solidity-frameworks/hardhat/packages/hardhat/test/YourContract.ts similarity index 100% rename from templates/extensions/hardhat/packages/hardhat/test/YourContract.ts rename to templates/solidity-frameworks/hardhat/packages/hardhat/test/YourContract.ts diff --git a/templates/extensions/hardhat/packages/hardhat/tsconfig.json b/templates/solidity-frameworks/hardhat/packages/hardhat/tsconfig.json similarity index 100% rename from templates/extensions/hardhat/packages/hardhat/tsconfig.json rename to templates/solidity-frameworks/hardhat/packages/hardhat/tsconfig.json diff --git a/templates/extensions/hardhat/packages/nextjs/app/blockexplorer/address/[address]/page.tsx.args.mjs b/templates/solidity-frameworks/hardhat/packages/nextjs/app/blockexplorer/address/[address]/page.tsx.args.mjs similarity index 100% rename from templates/extensions/hardhat/packages/nextjs/app/blockexplorer/address/[address]/page.tsx.args.mjs rename to templates/solidity-frameworks/hardhat/packages/nextjs/app/blockexplorer/address/[address]/page.tsx.args.mjs diff --git a/templates/extensions/hardhat/packages/nextjs/scaffold.config.ts.args.mjs b/templates/solidity-frameworks/hardhat/packages/nextjs/scaffold.config.ts.args.mjs similarity index 100% rename from templates/extensions/hardhat/packages/nextjs/scaffold.config.ts.args.mjs rename to templates/solidity-frameworks/hardhat/packages/nextjs/scaffold.config.ts.args.mjs