From 9b8610608442be2b27d232acecffe35244e51d2f Mon Sep 17 00:00:00 2001 From: Shiv Bhonde Date: Wed, 5 Jun 2024 14:59:26 +0530 Subject: [PATCH 01/12] remove handling of generated dir and yarn.lock file --- src/tasks/copy-template-files.ts | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/src/tasks/copy-template-files.ts b/src/tasks/copy-template-files.ts index e89b44f8a..f195b23a5 100644 --- a/src/tasks/copy-template-files.ts +++ b/src/tasks/copy-template-files.ts @@ -29,8 +29,6 @@ const expandExtensions = (options: Options): Extension[] => { const isTemplateRegex = /([^/\\]*?)\.template\./; const isPackageJsonRegex = /package\.json/; -const isYarnLockRegex = /yarn\.lock/; -const isNextGeneratedRegex = /packages\/nextjs\/generated/; const isConfigRegex = /([^/\\]*?)\\config\.json/; const isArgsRegex = /([^/\\]*?)\.args\./; const isExtensionFolderRegex = /extensions$/; @@ -40,40 +38,19 @@ const copyBaseFiles = async ({ dev: isDev }: Options, basePath: string, targetDi await copyOrLink(basePath, targetDir, { clobber: false, filter: fileName => { - // NOTE: filter IN const isTemplate = isTemplateRegex.test(fileName); const isPackageJson = isPackageJsonRegex.test(fileName); - const isYarnLock = isYarnLockRegex.test(fileName); - const isNextGenerated = isNextGeneratedRegex.test(fileName); - - const skipAlways = isTemplate || isPackageJson; - const skipDevOnly = isYarnLock || isNextGenerated; - const shouldSkip = skipAlways || (isDev && skipDevOnly); - + const shouldSkip = isTemplate || isPackageJson; + // filter in files that are not package.json or template files return !shouldSkip; }, }); const basePackageJsonPaths = findFilesRecursiveSync(basePath, path => isPackageJsonRegex.test(path)); - basePackageJsonPaths.forEach(packageJsonPath => { const partialPath = packageJsonPath.split(basePath)[1]; mergePackageJson(path.join(targetDir, partialPath), path.join(basePath, partialPath), isDev); }); - - if (isDev) { - const baseYarnLockPaths = findFilesRecursiveSync(basePath, path => isYarnLockRegex.test(path)); - baseYarnLockPaths.forEach(yarnLockPath => { - const partialPath = yarnLockPath.split(basePath)[1]; - void copy(path.join(basePath, partialPath), path.join(targetDir, partialPath)); - }); - - const nextGeneratedPaths = findFilesRecursiveSync(basePath, path => isNextGeneratedRegex.test(path)); - nextGeneratedPaths.forEach(nextGeneratedPath => { - const partialPath = nextGeneratedPath.split(basePath)[1]; - void copy(path.join(basePath, partialPath), path.join(targetDir, partialPath)); - }); - } }; const copyExtensionsFiles = async ({ dev: isDev }: Options, extensionPath: string, targetDir: string) => { @@ -293,6 +270,7 @@ export async function copyTemplateFiles(options: Options, templateDir: string, t await copyBaseFiles(options, basePath, targetDir); // 2. Add "parent" extensions (set via config.json#extend field) + // TODO: Revisit options.extensions = expandExtensions(options); // 3. Copy extensions folders From 6d88840cf819e38b1bae26d40a8cd023d78f1f24 Mon Sep 17 00:00:00 2001 From: Shiv Bhonde Date: Thu, 6 Jun 2024 21:39:11 +0530 Subject: [PATCH 02/12] allow undefined args to be passed by extensions --- src/tasks/copy-template-files.ts | 6 ++++-- templates/extensions/foundry/README.md.args.mjs | 1 - templates/extensions/hardhat/README.md.args.mjs | 1 - 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tasks/copy-template-files.ts b/src/tasks/copy-template-files.ts index f195b23a5..ee63262d4 100644 --- a/src/tasks/copy-template-files.ts +++ b/src/tasks/copy-template-files.ts @@ -188,13 +188,15 @@ const processTemplatedFiles = async ( ); } - // ToDo. Bug, if arg not present in arg[0], but present in arg[1], it will not be added. + const allKeys = [...new Set(args.flatMap(Object.keys))]; + const freshArgs: { [key: string]: string[] } = Object.fromEntries( - Object.keys(args[0] ?? {}).map(key => [ + allKeys.map(key => [ key, // INFO: key for the freshArgs object [], // INFO: initial value for the freshArgs object ]), ); + const combinedArgs = args.reduce((accumulated, arg) => { Object.entries(arg).map(([key, value]) => { accumulated[key]?.push(value); diff --git a/templates/extensions/foundry/README.md.args.mjs b/templates/extensions/foundry/README.md.args.mjs index f48ba4302..750d91ae8 100644 --- a/templates/extensions/foundry/README.md.args.mjs +++ b/templates/extensions/foundry/README.md.args.mjs @@ -3,4 +3,3 @@ export const networkConfigPath = `\`packages/foundry/foundry.toml\``; export const contractsPath = `\`packages/foundry/contracts\``; export const scriptsPath = `\`packages/foundry/script\``; export const testCommand = `\`yarn foundry:test\``; -export const extraContents = ""; diff --git a/templates/extensions/hardhat/README.md.args.mjs b/templates/extensions/hardhat/README.md.args.mjs index df7cc4bbf..a390c43e4 100644 --- a/templates/extensions/hardhat/README.md.args.mjs +++ b/templates/extensions/hardhat/README.md.args.mjs @@ -3,4 +3,3 @@ export const networkConfigPath = `\`packages/hardhat/hardhat.config.ts\``; export const contractsPath = `\`packages/hardhat/contracts\``; export const scriptsPath = `\`packages/hardhat/deploy\``; export const testCommand = `\`yarn hardhat:test\``; -export const extraContents = ""; From a5cc76f2700886958eafc2f3ec9fb238bdb7aa14 Mon Sep 17 00:00:00 2001 From: Shiv Bhonde Date: Thu, 6 Jun 2024 22:56:09 +0530 Subject: [PATCH 03/12] simplify copyBaseFiles --- src/tasks/copy-template-files.ts | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/tasks/copy-template-files.ts b/src/tasks/copy-template-files.ts index ee63262d4..df1102ca4 100644 --- a/src/tasks/copy-template-files.ts +++ b/src/tasks/copy-template-files.ts @@ -34,23 +34,14 @@ const isArgsRegex = /([^/\\]*?)\.args\./; const isExtensionFolderRegex = /extensions$/; const isPackagesFolderRegex = /packages$/; -const copyBaseFiles = async ({ dev: isDev }: Options, basePath: string, targetDir: string) => { +const copyBaseFiles = async (_options: Options, basePath: string, targetDir: string) => { await copyOrLink(basePath, targetDir, { clobber: false, filter: fileName => { const isTemplate = isTemplateRegex.test(fileName); - const isPackageJson = isPackageJsonRegex.test(fileName); - const shouldSkip = isTemplate || isPackageJson; - // filter in files that are not package.json or template files - return !shouldSkip; + return !isTemplate; }, }); - - const basePackageJsonPaths = findFilesRecursiveSync(basePath, path => isPackageJsonRegex.test(path)); - basePackageJsonPaths.forEach(packageJsonPath => { - const partialPath = packageJsonPath.split(basePath)[1]; - mergePackageJson(path.join(targetDir, partialPath), path.join(basePath, partialPath), isDev); - }); }; const copyExtensionsFiles = async ({ dev: isDev }: Options, extensionPath: string, targetDir: string) => { From e95f6b7126c43bee770f74cd6c5186d9449260c6 Mon Sep 17 00:00:00 2001 From: Shiv Bhonde Date: Fri, 7 Jun 2024 10:52:51 +0530 Subject: [PATCH 04/12] remove passing of extra option argument from copyBaseFiles --- src/tasks/copy-template-files.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tasks/copy-template-files.ts b/src/tasks/copy-template-files.ts index df1102ca4..6aa8cc7e8 100644 --- a/src/tasks/copy-template-files.ts +++ b/src/tasks/copy-template-files.ts @@ -34,7 +34,7 @@ const isArgsRegex = /([^/\\]*?)\.args\./; const isExtensionFolderRegex = /extensions$/; const isPackagesFolderRegex = /packages$/; -const copyBaseFiles = async (_options: Options, basePath: string, targetDir: string) => { +const copyBaseFiles = async (basePath: string, targetDir: string) => { await copyOrLink(basePath, targetDir, { clobber: false, filter: fileName => { @@ -260,7 +260,7 @@ export async function copyTemplateFiles(options: Options, templateDir: string, t const tmpDir = path.join(targetDir, EXTERNAL_EXTENSION_TMP_FOLDER); // 1. Copy base template to target directory - await copyBaseFiles(options, basePath, targetDir); + await copyBaseFiles(basePath, targetDir); // 2. Add "parent" extensions (set via config.json#extend field) // TODO: Revisit From 21c75a104876be2c30494176bb3b5e4d68a6561c Mon Sep 17 00:00:00 2001 From: Shiv Bhonde Date: Wed, 12 Jun 2024 11:56:19 +0530 Subject: [PATCH 05/12] remove logic nested-extension + extends extension --- src/tasks/copy-template-files.ts | 27 +++-------- src/types.ts | 11 ----- src/utils/extensions-tree.ts | 62 +++++++++++-------------- src/utils/prompt-for-missing-options.ts | 48 ++----------------- 4 files changed, 35 insertions(+), 113 deletions(-) diff --git a/src/tasks/copy-template-files.ts b/src/tasks/copy-template-files.ts index 6aa8cc7e8..6e48084e8 100644 --- a/src/tasks/copy-template-files.ts +++ b/src/tasks/copy-template-files.ts @@ -1,5 +1,5 @@ import { execa } from "execa"; -import { Extension, isDefined, Options, TemplateDescriptor } from "../types"; +import { Options, TemplateDescriptor } from "../types"; import { baseDir } from "../utils/consts"; import { extensionDict } from "../utils/extensions-tree"; import { findFilesRecursiveSync } from "../utils/find-files-recursively"; @@ -16,17 +16,6 @@ const EXTERNAL_EXTENSION_TMP_FOLDER = "tmp-external-extension"; const copy = promisify(ncp); let copyOrLink = copy; -const expandExtensions = (options: Options): Extension[] => { - const expandedExtensions = options.extensions - .map(extension => extensionDict[extension]) - .map(extDescriptor => [extDescriptor.extends, extDescriptor.value].filter(isDefined)) - .flat() - // this reduce just removes duplications - .reduce((exts, ext) => (exts.includes(ext) ? exts : [...exts, ext]), [] as Extension[]); - - return expandedExtensions; -}; - const isTemplateRegex = /([^/\\]*?)\.template\./; const isPackageJsonRegex = /package\.json/; const isConfigRegex = /([^/\\]*?)\\config\.json/; @@ -262,11 +251,7 @@ export async function copyTemplateFiles(options: Options, templateDir: string, t // 1. Copy base template to target directory await copyBaseFiles(basePath, targetDir); - // 2. Add "parent" extensions (set via config.json#extend field) - // TODO: Revisit - options.extensions = expandExtensions(options); - - // 3. Copy extensions folders + // 2. Copy extensions folders await Promise.all( options.extensions.map(async extension => { const extensionPath = extensionDict[extension].path; @@ -274,21 +259,21 @@ export async function copyTemplateFiles(options: Options, templateDir: string, t }), ); - // 4. Set up external extension if needed + // 3. Set up external extension if needed if (options.externalExtension) { await setUpExternalExtensionFiles(options, tmpDir); await copyExtensionsFiles(options, path.join(tmpDir, "extension"), targetDir); } - // 5. Process templated files and generate output + // 4. Process templated files and generate output await processTemplatedFiles(options, basePath, targetDir); - // 6. Delete tmp directory + // 5. Delete tmp directory if (options.externalExtension) { await fs.promises.rm(tmpDir, { recursive: true }); } - // 7. Initialize git repo to avoid husky error + // 6. Initialize git repo to avoid husky error await execa("git", ["init"], { cwd: targetDir }); await execa("git", ["checkout", "-b", "main"], { cwd: targetDir }); } diff --git a/src/types.ts b/src/types.ts index 4b07439e7..28d46d907 100644 --- a/src/types.ts +++ b/src/types.ts @@ -60,23 +60,12 @@ export type ExtensionDescriptor = { name: string; value: Extension; path: string; - extensions?: Extension[]; - extends?: Extension; }; -export type ExtensionBranch = ExtensionDescriptor & { - extensions: Extension[]; -}; export type ExtensionDict = { [extension in Extension]: ExtensionDescriptor; }; -export const extensionWithSubextensions = ( - extension: ExtensionDescriptor | undefined, -): extension is ExtensionBranch => { - return Object.prototype.hasOwnProperty.call(extension, "extensions"); -}; - export type TemplateDescriptor = { path: string; fileUrl: string; diff --git a/src/utils/extensions-tree.ts b/src/utils/extensions-tree.ts index 70f02541d..ab15fb423 100644 --- a/src/utils/extensions-tree.ts +++ b/src/utils/extensions-tree.ts @@ -15,7 +15,7 @@ const templatesDirectory = path.resolve(decodeURI(fileURLToPath(currentFileUrl)) * @param basePath the path at which to start the traverse * @returns the extensions found in this path. Useful for the recursion */ -const traverseExtensions = async (basePath: string): Promise => { +const traverseExtensions = (basePath: string): Extension[] => { const extensionsPath = path.resolve(basePath, "extensions"); let extensions: Extension[]; try { @@ -24,45 +24,35 @@ const traverseExtensions = async (basePath: string): Promise => { return []; } - await Promise.all( - extensions.map(async 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}`, - ); - } + 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 name = config.name ?? ext; + const value = ext; - const subExtensions = await traverseExtensions(extPath); - const hasSubExtensions = subExtensions.length !== 0; - const extDescriptor: ExtensionDescriptor = { - name, - value, - path: extPath, - extensions: subExtensions, - extends: config.extends as Extension | undefined, - }; - if (!hasSubExtensions) { - delete extDescriptor.extensions; - } - extensionDict[ext] = extDescriptor; + const extDescriptor: ExtensionDescriptor = { + name, + value, + path: extPath, + }; - return subExtensions; - }), - ); + extensionDict[ext] = extDescriptor; + }); return extensions; }; -await traverseExtensions(templatesDirectory); +traverseExtensions(templatesDirectory); diff --git a/src/utils/prompt-for-missing-options.ts b/src/utils/prompt-for-missing-options.ts index 93d9e9bfa..4f478f920 100644 --- a/src/utils/prompt-for-missing-options.ts +++ b/src/utils/prompt-for-missing-options.ts @@ -1,14 +1,6 @@ import { config } from "../config"; -import { - Extension, - ExtensionDescriptor, - Options, - RawOptions, - extensionWithSubextensions, - isDefined, - isExtension, -} from "../types"; -import inquirer, { Answers } from "inquirer"; +import { Extension, Options, RawOptions, isDefined, isExtension } from "../types"; +import inquirer from "inquirer"; import { extensionDict } from "./extensions-tree"; // default values for unspecified args @@ -38,26 +30,6 @@ export async function promptForMissingOptions(options: RawOptions): Promise value.length > 0, }); - const recurringAddFollowUps = (extensions: ExtensionDescriptor[], relatedQuestion: string) => { - extensions.filter(extensionWithSubextensions).forEach(ext => { - const nestedExtensions = ext.extensions.map(nestedExt => extensionDict[nestedExt]); - questions.push({ - // INFO: assuming nested extensions are all optional. To change this, - // update ExtensionDescriptor adding type, and update code here. - type: "checkbox", - name: `${ext.value}-extensions`, - message: `Select optional extensions for ${ext.name}`, - choices: nestedExtensions, - when: (answers: Answers) => { - const relatedResponse = answers[relatedQuestion]; - const wasMultiselectResponse = Array.isArray(relatedResponse); - return wasMultiselectResponse ? relatedResponse.includes(ext.value) : relatedResponse === ext.value; - }, - }); - recurringAddFollowUps(nestedExtensions, `${ext.value}-extensions`); - }); - }; - config.questions.forEach(question => { if (invalidQuestionNames.includes(question.name)) { throw new Error( @@ -66,6 +38,7 @@ export async function promptForMissingOptions(options: RawOptions): Promise extensionDict[ext]) @@ -79,8 +52,6 @@ export async function promptForMissingOptions(options: RawOptions): Promise { - baseExtensions.forEach(extValue => { - const nestedExtKey = `${extValue}-extensions`; - const nestedExtensions = answers[nestedExtKey]; - if (nestedExtensions) { - mergedOptions.extensions.push(...nestedExtensions); - recurringAddNestedExtensions(nestedExtensions); - } - }); - }; - - recurringAddNestedExtensions(mergedOptions.extensions); - return mergedOptions; } From 962db91adcbdcd1031bef7c5f707b4a1b8a3f1e9 Mon Sep 17 00:00:00 2001 From: Shiv Bhonde Date: Wed, 12 Jun 2024 12:17:47 +0530 Subject: [PATCH 06/12] remove dangling TODO --- src/tasks/copy-template-files.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tasks/copy-template-files.ts b/src/tasks/copy-template-files.ts index 6e48084e8..d12ecb32d 100644 --- a/src/tasks/copy-template-files.ts +++ b/src/tasks/copy-template-files.ts @@ -184,8 +184,6 @@ const processTemplatedFiles = async ( return accumulated; }, freshArgs); - // TODO test: if first arg file found only uses 1 name, I think the rest are not used? - const output = fileTemplate(combinedArgs); const targetPath = path.join( From e7b5b33f88d7b368ce3182ab366f543a4a86278d Mon Sep 17 00:00:00 2001 From: Shiv Bhonde Date: Wed, 12 Jun 2024 12:35:08 +0530 Subject: [PATCH 07/12] tidy up extension-tree.ts file --- src/tasks/copy-template-files.ts | 2 +- ...ensions-tree.ts => extensions-dictionary.ts} | 17 ++++++++--------- src/utils/prompt-for-missing-options.ts | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) rename src/utils/{extensions-tree.ts => extensions-dictionary.ts} (72%) diff --git a/src/tasks/copy-template-files.ts b/src/tasks/copy-template-files.ts index d12ecb32d..6eb1266fd 100644 --- a/src/tasks/copy-template-files.ts +++ b/src/tasks/copy-template-files.ts @@ -1,7 +1,7 @@ import { execa } from "execa"; import { Options, TemplateDescriptor } from "../types"; import { baseDir } from "../utils/consts"; -import { extensionDict } from "../utils/extensions-tree"; +import { extensionDict } from "../utils/extensions-dictionary"; import { findFilesRecursiveSync } from "../utils/find-files-recursively"; import { mergePackageJson } from "../utils/merge-package-json"; import fs from "fs"; diff --git a/src/utils/extensions-tree.ts b/src/utils/extensions-dictionary.ts similarity index 72% rename from src/utils/extensions-tree.ts rename to src/utils/extensions-dictionary.ts index ab15fb423..b7862e410 100644 --- a/src/utils/extensions-tree.ts +++ b/src/utils/extensions-dictionary.ts @@ -3,6 +3,7 @@ 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; @@ -10,18 +11,16 @@ const currentFileUrl = import.meta.url; const templatesDirectory = path.resolve(decodeURI(fileURLToPath(currentFileUrl)), "../../templates"); /** - * This function has side effects. It generates the extensionDict. - * - * @param basePath the path at which to start the traverse - * @returns the extensions found in this path. Useful for the recursion + * This function has side effects. It initializes the extensionDict. */ -const traverseExtensions = (basePath: string): Extension[] => { +const initializeExtensionsDict = (basePath: string) => { const extensionsPath = path.resolve(basePath, "extensions"); let extensions: Extension[]; try { extensions = fs.readdirSync(extensionsPath) as Extension[]; } catch (error) { - return []; + console.error(`Couldn't read the extensions directory: ${extensionsPath}`); + return; } extensions.forEach(ext => { @@ -51,8 +50,8 @@ Config file path: ${configPath}`, extensionDict[ext] = extDescriptor; }); - - return extensions; }; -traverseExtensions(templatesDirectory); +// 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/prompt-for-missing-options.ts b/src/utils/prompt-for-missing-options.ts index 4f478f920..51caa9524 100644 --- a/src/utils/prompt-for-missing-options.ts +++ b/src/utils/prompt-for-missing-options.ts @@ -1,7 +1,7 @@ import { config } from "../config"; import { Extension, Options, RawOptions, isDefined, isExtension } from "../types"; import inquirer from "inquirer"; -import { extensionDict } from "./extensions-tree"; +import { extensionDict } from "./extensions-dictionary"; // default values for unspecified args const defaultOptions: RawOptions = { From 8e4323c1252581dcbc9694a80bc5c9c1d997979b Mon Sep 17 00:00:00 2001 From: Shiv Bhonde Date: Wed, 12 Jun 2024 15:14:47 +0530 Subject: [PATCH 08/12] remove nested and extending section from RFC.md file --- contributors/RFC-extensions.md | 62 ++-------------------------------- 1 file changed, 2 insertions(+), 60 deletions(-) diff --git a/contributors/RFC-extensions.md b/contributors/RFC-extensions.md index d2dbeb5dd..8f424cda3 100644 --- a/contributors/RFC-extensions.md +++ b/contributors/RFC-extensions.md @@ -6,62 +6,6 @@ This change should make it easier to grow the options we provide our users witho 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. -## Nested extensions - -We can add extensions of extensions, just by adding an `/extensions` folder inside an existing extension. For example, adding [next-auth][1] as an extension for next would look something like the following: - -```text -create-dapp-example/ -├─ src/ -│ ├─ ... -│ -├─ templates/ -│ ├─ base/ -│ ├─ extensions/ -│ │ ├─nextjs -│ │ ├─ ... -│ │ ├─ extensions/ -│ │ │ ├─ next-auth/ -│ │ │ ├─ ... -``` - -## Extending extensions - -> sorry for the confusing naming - -Extensions can also inherit (or extend) another extension. The goal of this feature is that two extensions can share files or nested extensions without duplication. An example of this could be hardhat and foundry, which are two different extensions, but both of them could have a shared UI to debug smart contracts. - -The file structure could be like this: - -```text -create-dapp-example/ -├─ src/ -│ ├─ ... -│ -├─ templates/ -│ ├─ base/ -│ ├─ extensions/ -│ │ ├─ foundry/ -│ │ │ ├─ config.json <- important to declare the `extends` field here -│ │ │ ├─ ... -│ │ ├─ hardhat/ -│ │ │ ├─ config.json <- important to declare the `extends` field here -│ │ │ ├─ ... -│ │ ├─ common/ -│ │ │ ├─ extensions/ -│ │ │ │ ├─ possible-shared-nested-extension/ -│ │ │ │ ├─ ... -│ │ │ ├─ shared-file.md -``` - -For `foundry` and `hardhat` extensions to inherit from `common`, they need to add the `extends` field to the config.json file. - -```json -{ - "extends": "common" -} -``` - # Config files There's one main `src/config.ts` file to configure the questions shown to the user. @@ -86,14 +30,12 @@ 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. -- `extends`: the name of a different extension used as "parent extension". Read more at the [Extending extensions](#extending-extensions) section - 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-tree.ts file so the new field from the config is actually added into the extension descriptor +| - Update the src/utils/extensions-dictionary.ts file so the new field from the config is actually added into the extension descriptor # Template files @@ -270,7 +212,7 @@ The special files and folders are: - [`package.json` file](#merging-packagejson-files) - [`config.json` file](#extensionconfigjson) -- [`extensions/` folder](#nested-extensions) +- `extensions/` folder # Things worth mentioning From 91d3d3354dbc43770be6542b7fccb5f19ca0b738 Mon Sep 17 00:00:00 2001 From: Shiv Bhonde Date: Thu, 13 Jun 2024 20:19:29 +0530 Subject: [PATCH 09/12] remove handlebars from dependency --- package.json | 1 - yarn.lock | 56 ---------------------------------------------------- 2 files changed, 57 deletions(-) diff --git a/package.json b/package.json index 2932dca02..632d38480 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,6 @@ "arg": "5.0.2", "chalk": "5.2.0", "execa": "7.1.1", - "handlebars": "^4.7.7", "inquirer": "9.2.0", "listr": "0.14.3", "merge-packages": "^0.1.6", diff --git a/yarn.lock b/yarn.lock index db4c11dfa..09d3d6483 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1429,7 +1429,6 @@ __metadata: eslint-config-prettier: ^9.1.0 eslint-plugin-prettier: ^5.1.3 execa: 7.1.1 - handlebars: ^4.7.7 husky: ^9.0.11 inquirer: 9.2.0 lint-staged: ^15.2.4 @@ -2513,24 +2512,6 @@ __metadata: languageName: node linkType: hard -"handlebars@npm:^4.7.7": - version: 4.7.7 - resolution: "handlebars@npm:4.7.7" - dependencies: - minimist: ^1.2.5 - neo-async: ^2.6.0 - source-map: ^0.6.1 - uglify-js: ^3.1.4 - wordwrap: ^1.0.0 - dependenciesMeta: - uglify-js: - optional: true - bin: - handlebars: bin/handlebars - checksum: 1e79a43f5e18d15742977cb987923eab3e2a8f44f2d9d340982bcb69e1735ed049226e534d7c1074eaddaf37e4fb4f471a8adb71cddd5bc8cf3f894241df5cee - languageName: node - linkType: hard - "hard-rejection@npm:^2.1.0": version: 2.1.0 resolution: "hard-rejection@npm:2.1.0" @@ -3672,13 +3653,6 @@ __metadata: languageName: node linkType: hard -"minimist@npm:^1.2.5": - version: 1.2.8 - resolution: "minimist@npm:1.2.8" - checksum: 75a6d645fb122dad29c06a7597bddea977258957ed88d7a6df59b5cd3fe4a527e253e9bbf2e783e4b73657f9098b96a5fe96ab8a113655d4109108577ecf85b0 - languageName: node - linkType: hard - "minipass-collect@npm:^1.0.2": version: 1.0.2 resolution: "minipass-collect@npm:1.0.2" @@ -3816,13 +3790,6 @@ __metadata: languageName: node linkType: hard -"neo-async@npm:^2.6.0": - version: 2.6.2 - resolution: "neo-async@npm:2.6.2" - checksum: deac9f8d00eda7b2e5cd1b2549e26e10a0faa70adaa6fdadca701cc55f49ee9018e427f424bac0c790b7c7e2d3068db97f3093f1093975f2acb8f8818b936ed9 - languageName: node - linkType: hard - "nice-try@npm:^1.0.4": version: 1.0.5 resolution: "nice-try@npm:1.0.5" @@ -4864,13 +4831,6 @@ __metadata: languageName: node linkType: hard -"source-map@npm:^0.6.1": - version: 0.6.1 - resolution: "source-map@npm:0.6.1" - checksum: 59ce8640cf3f3124f64ac289012c2b8bd377c238e316fb323ea22fbfe83da07d81e000071d7242cad7a23cd91c7de98e4df8830ec3f133cb6133a5f6e9f67bc2 - languageName: node - linkType: hard - "spawndamnit@npm:^2.0.0": version: 2.0.0 resolution: "spawndamnit@npm:2.0.0" @@ -5410,15 +5370,6 @@ __metadata: languageName: node linkType: hard -"uglify-js@npm:^3.1.4": - version: 3.17.4 - resolution: "uglify-js@npm:3.17.4" - bin: - uglifyjs: bin/uglifyjs - checksum: 7b3897df38b6fc7d7d9f4dcd658599d81aa2b1fb0d074829dd4e5290f7318dbca1f4af2f45acb833b95b1fe0ed4698662ab61b87e94328eb4c0a0d3435baf924 - languageName: node - linkType: hard - "unbox-primitive@npm:^1.0.2": version: 1.0.2 resolution: "unbox-primitive@npm:1.0.2" @@ -5579,13 +5530,6 @@ __metadata: languageName: node linkType: hard -"wordwrap@npm:^1.0.0": - version: 1.0.0 - resolution: "wordwrap@npm:1.0.0" - checksum: 2a44b2788165d0a3de71fd517d4880a8e20ea3a82c080ce46e294f0b68b69a2e49cff5f99c600e275c698a90d12c5ea32aff06c311f0db2eb3f1201f3e7b2a04 - languageName: node - linkType: hard - "wrap-ansi@npm:^3.0.1": version: 3.0.1 resolution: "wrap-ansi@npm:3.0.1" From 3660a05979063998b99f57730b381eaafaf0024f Mon Sep 17 00:00:00 2001 From: Shiv Bhonde Date: Fri, 14 Jun 2024 19:51:20 +0530 Subject: [PATCH 10/12] don't symlink yarn.lock in dev mode --- src/tasks/copy-template-files.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/tasks/copy-template-files.ts b/src/tasks/copy-template-files.ts index 6eb1266fd..e1469e0f0 100644 --- a/src/tasks/copy-template-files.ts +++ b/src/tasks/copy-template-files.ts @@ -18,19 +18,31 @@ let copyOrLink = copy; const isTemplateRegex = /([^/\\]*?)\.template\./; const isPackageJsonRegex = /package\.json/; +const isYarnLockRegex = /yarn\.lock/; const isConfigRegex = /([^/\\]*?)\\config\.json/; const isArgsRegex = /([^/\\]*?)\.args\./; const isExtensionFolderRegex = /extensions$/; const isPackagesFolderRegex = /packages$/; -const copyBaseFiles = async (basePath: string, targetDir: string) => { +const copyBaseFiles = async (basePath: string, targetDir: string, { dev: isDev }: Options) => { await copyOrLink(basePath, targetDir, { clobber: false, filter: fileName => { + const isYarnLock = isYarnLockRegex.test(fileName); const isTemplate = isTemplateRegex.test(fileName); - return !isTemplate; + const skipDevOnly = isDev && isYarnLock; + return !isTemplate || !skipDevOnly; }, }); + + if (isDev) { + // we don't want to symlink the yarn.lock file + const baseYarnLockPaths = findFilesRecursiveSync(basePath, path => isYarnLockRegex.test(path)); + baseYarnLockPaths.forEach(yarnLockPath => { + const partialPath = yarnLockPath.split(basePath)[1]; + void copy(path.join(basePath, partialPath), path.join(targetDir, partialPath)); + }); + } }; const copyExtensionsFiles = async ({ dev: isDev }: Options, extensionPath: string, targetDir: string) => { @@ -247,7 +259,7 @@ export async function copyTemplateFiles(options: Options, templateDir: string, t const tmpDir = path.join(targetDir, EXTERNAL_EXTENSION_TMP_FOLDER); // 1. Copy base template to target directory - await copyBaseFiles(basePath, targetDir); + await copyBaseFiles(basePath, targetDir, options); // 2. Copy extensions folders await Promise.all( From 4ac42dc3270fd4cfc98193c5d2d3d6c0e2f9fec2 Mon Sep 17 00:00:00 2001 From: Shiv Bhonde Date: Fri, 14 Jun 2024 20:23:08 +0530 Subject: [PATCH 11/12] don't symlink deployedContracts.ts in dev mode --- src/tasks/copy-template-files.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/tasks/copy-template-files.ts b/src/tasks/copy-template-files.ts index e1469e0f0..1ab981b94 100644 --- a/src/tasks/copy-template-files.ts +++ b/src/tasks/copy-template-files.ts @@ -23,25 +23,35 @@ const isConfigRegex = /([^/\\]*?)\\config\.json/; const isArgsRegex = /([^/\\]*?)\.args\./; const isExtensionFolderRegex = /extensions$/; const isPackagesFolderRegex = /packages$/; +const isDeployedContractsRegex = /packages\/nextjs\/contracts\/deployedContracts\.ts/; const copyBaseFiles = async (basePath: string, targetDir: string, { dev: isDev }: Options) => { await copyOrLink(basePath, targetDir, { clobber: false, filter: fileName => { - const isYarnLock = isYarnLockRegex.test(fileName); const isTemplate = isTemplateRegex.test(fileName); - const skipDevOnly = isDev && isYarnLock; - return !isTemplate || !skipDevOnly; + + const isYarnLock = isYarnLockRegex.test(fileName); + const isDeployedContracts = isDeployedContractsRegex.test(fileName); + const skipDevOnly = isDev && (isYarnLock || isDeployedContracts); + + return !isTemplate && !skipDevOnly; }, }); if (isDev) { - // we don't want to symlink the yarn.lock file + // we don't want to symlink yarn.lock & deployedContracts.ts file const baseYarnLockPaths = findFilesRecursiveSync(basePath, path => isYarnLockRegex.test(path)); baseYarnLockPaths.forEach(yarnLockPath => { const partialPath = yarnLockPath.split(basePath)[1]; void copy(path.join(basePath, partialPath), path.join(targetDir, partialPath)); }); + + const baseDeployedContractsPaths = findFilesRecursiveSync(basePath, path => isDeployedContractsRegex.test(path)); + baseDeployedContractsPaths.forEach(deployedContractsPath => { + const partialPath = deployedContractsPath.split(basePath)[1]; + void copy(path.join(basePath, partialPath), path.join(targetDir, partialPath)); + }); } }; From 207e3d9c3829bb83aeabe4919eb22b44fb315571 Mon Sep 17 00:00:00 2001 From: Shiv Bhonde Date: Fri, 14 Jun 2024 21:16:23 +0530 Subject: [PATCH 12/12] rename rfc-extensions to core-extensions --- contributors/{RFC-extensions.md => core-extensions.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename contributors/{RFC-extensions.md => core-extensions.md} (100%) diff --git a/contributors/RFC-extensions.md b/contributors/core-extensions.md similarity index 100% rename from contributors/RFC-extensions.md rename to contributors/core-extensions.md