dappbooster 0.3.3 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.nvmrc ADDED
@@ -0,0 +1 @@
1
+ 20
package/.prettierrc ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "bracketSpacing": true,
3
+ "printWidth": 100,
4
+ "semi": false,
5
+ "singleQuote": true,
6
+ "trailingComma": "all"
7
+ }
package/README.md CHANGED
@@ -1,9 +1,36 @@
1
1
  # dAppBooster starter
2
2
 
3
- A script to clone dAppBooster and cleanup the history to freshly start your new project
3
+ A script to clone dAppBooster and cleanup the history to freshly start your new project.
4
4
 
5
- # Usage
5
+ Clones the latest tag from https://github.com/BootNodeDev/dAppBooster (so you might not see the last changes in `main`).
6
+
7
+ ## Usage
8
+
9
+ ```shell
10
+ $ pnpm dlx dappbooster <projectName>
11
+ ```
12
+
13
+ ## Development
14
+
15
+ Move into the script's folder and then
6
16
 
7
17
  ```shell
8
- $ pnpx dappbooster <projectDirectory>
18
+ # Clone the repo
19
+ git clone git@github.com:BootNodeDev/dAppBooster-starter.git
20
+
21
+ # Install dependencies
22
+ pnpm i
23
+
24
+ # Move into the script's folder
25
+ cd dAppBooster-starter
9
26
  ```
27
+
28
+ The common loop for testing the script looks something like
29
+
30
+ ```shell
31
+ # Test the script, creates a folder called test
32
+ $ node index.js test
33
+
34
+ # Remove the test directory (ignored in .gitignore)
35
+ $ rm -rf test
36
+ ```
@@ -0,0 +1,17 @@
1
+ export const repoUrl = 'https://github.com/BootNodeDev/dAppBooster.git'
2
+ export const homeFolder = '/src/components/pageComponents/home'
3
+
4
+ export const defaultExecOptions = {
5
+ stdio: 'pipe',
6
+ shell: true,
7
+ }
8
+
9
+ export const fileExecOptions = {
10
+ recursive: true,
11
+ force: true,
12
+ }
13
+
14
+ export const installPackageExecOptions = {
15
+ stdio: 'inherit',
16
+ shell: true,
17
+ }
package/import/git.js ADDED
@@ -0,0 +1,56 @@
1
+ import { execSync } from 'node:child_process'
2
+ import { rmSync } from 'node:fs'
3
+ import os from 'node:os'
4
+ import { join } from 'node:path'
5
+ import chalk from 'chalk'
6
+ import { defaultExecOptions, fileExecOptions, repoUrl } from './config.js'
7
+
8
+ /**
9
+ * @description Get the latest tag from the repository
10
+ * @returns {string} The latest tag
11
+ */
12
+ function getLatestTag() {
13
+ const commandSilencer = os.platform() === 'win32' ? '> nul 2>&1' : '> /dev/null 2>&1'
14
+
15
+ execSync(`git fetch --tags ${commandSilencer}`, defaultExecOptions)
16
+
17
+ const tags = execSync('git tag -l --sort=-v:refname').toString().trim().split('\n')
18
+
19
+ return tags[0]
20
+ }
21
+
22
+ /**
23
+ * @description Clone the repository
24
+ */
25
+ export function cloneRepo(projectName) {
26
+ const projectDir = join(process.cwd(), projectName)
27
+
28
+ try {
29
+ console.log(`Cloning dAppBooster in ${chalk.bold(`${projectName}`)}`)
30
+ execSync(`git clone --depth 1 --no-checkout "${repoUrl}" "${projectDir}"`, defaultExecOptions)
31
+
32
+ process.chdir(projectDir)
33
+
34
+ const latestTag = getLatestTag(defaultExecOptions)
35
+
36
+ if (latestTag) {
37
+ console.log(`Checking out latest tag`)
38
+ execSync(`git checkout "${latestTag}"`, defaultExecOptions)
39
+ } else {
40
+ console.log(`No tags found, checking out ${chalk.bold('main')} branch...`)
41
+ execSync('git checkout main', defaultExecOptions)
42
+ }
43
+
44
+ // Remove .git, and initialize the repo
45
+ rmSync(join(projectDir, '.git'), fileExecOptions)
46
+ execSync('git init', defaultExecOptions)
47
+
48
+ console.log(`Repository cloned in ${chalk.bold(projectDir)}`)
49
+ console.log(`Version: ${latestTag ? chalk.bold(latestTag) : chalk.bold('main')}`)
50
+ } catch (error) {
51
+ console.error(`${chalk.bold.red('An error occurred:')}`, error.message)
52
+ process.exit(1)
53
+ }
54
+
55
+ console.log('\n---\n')
56
+ }
@@ -0,0 +1,200 @@
1
+ import { execSync } from 'node:child_process'
2
+ import { existsSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
3
+ import { join } from 'node:path'
4
+ import chalk from 'chalk'
5
+ import { defaultExecOptions, fileExecOptions, homeFolder, installPackageExecOptions } from './config.js'
6
+
7
+ /**
8
+ * @description Create the .env.local file
9
+ */
10
+ export function createEnvFile() {
11
+ const envFilePath = join(process.cwd(), '.env.local')
12
+ const exampleFilePath = join(process.cwd(), '.env.example')
13
+
14
+ execSync(`cp ${exampleFilePath} ${envFilePath}`, defaultExecOptions)
15
+ }
16
+
17
+ /**
18
+ * @description Install project packages, remove unwanted ones.
19
+ */
20
+ export function installPackages(
21
+ demoSupport,
22
+ subgraphSupport,
23
+ typedocSupport,
24
+ vocsSupport,
25
+ huskySupport,
26
+ ) {
27
+ const subgraphPackages = !subgraphSupport
28
+ ? [
29
+ '@bootnodedev/db-subgraph',
30
+ 'graphql graphql-request',
31
+ '@graphql-codegen/cli',
32
+ '@graphql-typed-document-node/core',
33
+ ]
34
+ : []
35
+ const typedocPackages = !typedocSupport
36
+ ? [
37
+ 'typedoc',
38
+ 'typedoc-github-theme',
39
+ 'typedoc-plugin-inline-sources',
40
+ 'typedoc-plugin-missing-exports',
41
+ 'typedoc-plugin-rename-defaults',
42
+ ]
43
+ : []
44
+ const vocsPackages = !vocsSupport ? ['vocs'] : []
45
+ const huskyPackages = !huskySupport
46
+ ? ['husky', 'lint-staged', '@commitlint/cli', '@commitlint/config-conventional']
47
+ : []
48
+
49
+ const packagesToRemove = [
50
+ ...subgraphPackages,
51
+ ...typedocPackages,
52
+ ...vocsPackages,
53
+ ...huskyPackages,
54
+ ]
55
+
56
+ console.log('\n---\n')
57
+ console.log(`Installing packages...`)
58
+
59
+ // Remove demo files
60
+ if (!demoSupport) {
61
+ demoFilesCleanup()
62
+ }
63
+
64
+ console.log('\n---\n')
65
+
66
+ if (!packagesToRemove.length) {
67
+ execSync('pnpm install --loglevel warn', installPackageExecOptions)
68
+ console.log('\n---\n')
69
+ } else {
70
+ // pnpm remove will install the necessary packages while uninstalling the unwanted ones...
71
+ execSync(`pnpm remove ${packagesToRemove.join(' ')} --loglevel warn`, installPackageExecOptions)
72
+ // ... but it won't run the post-install script, so we run it manually
73
+ execSync(`pnpm run postinstall`, installPackageExecOptions)
74
+ console.log('\n---\n')
75
+
76
+ // Remove package-related files and scripts
77
+ packageFilesCleanup(subgraphSupport, typedocSupport, vocsSupport, huskySupport)
78
+ }
79
+
80
+ // Remove installer files
81
+ installFilesCleanup()
82
+ console.log('\n---\n')
83
+ }
84
+
85
+ /**
86
+ * @description Removes demo-related folders and files
87
+ */
88
+ function demoFilesCleanup() {
89
+ const absoluteHomeFolder = join(process.cwd(), homeFolder)
90
+
91
+ console.log(`${chalk.bold.red('Removing')} demo list`)
92
+
93
+ rmSync(absoluteHomeFolder, fileExecOptions)
94
+
95
+ execSync(`mkdir -p ${absoluteHomeFolder}`, defaultExecOptions)
96
+ execSync(
97
+ `cp ${join(process.cwd(), '.install-files/home/index.tsx')} ${absoluteHomeFolder}`,
98
+ defaultExecOptions,
99
+ )
100
+ }
101
+
102
+ /**
103
+ * @description Removes:
104
+ * - Subgraphs folder
105
+ * - Subgraph demos and references to them in the demos list
106
+ */
107
+ function subgraphCleanup() {
108
+ const demoListFile = join(process.cwd(), `${homeFolder}/Examples/index.tsx`)
109
+
110
+ // Remove the root subgraphs folder
111
+ rmSync(join(process.cwd(), '/src/subgraphs'), fileExecOptions)
112
+
113
+ // Only remove the subgraph demos if the user kept the demo list
114
+ if (existsSync(demoListFile)) {
115
+ // Remove the subgraph demos
116
+ rmSync(join(process.cwd(), `${homeFolder}/Examples/demos/subgraphs`), fileExecOptions)
117
+
118
+ // Remove the list...
119
+ rmSync(demoListFile, { force: true })
120
+
121
+ // ... and replace it by the list with no subgraph demos
122
+ execSync(
123
+ `cp ${join(process.cwd(), `.install-files/home/Examples/index.tsx`)} ${demoListFile}`,
124
+ defaultExecOptions,
125
+ )
126
+ }
127
+ }
128
+
129
+ /**
130
+ * @description Removes typedoc files
131
+ */
132
+ function typedocCleanup() {
133
+ rmSync(join(process.cwd(), 'typedoc.json'), fileExecOptions)
134
+ rmSync(join(process.cwd(), '.github/workflows/typedoc.yml'), fileExecOptions)
135
+ }
136
+
137
+ /**
138
+ * @description Removes Vocs files
139
+ */
140
+ function vocsCleanup() {
141
+ rmSync(join(process.cwd(), 'vocs.config.ts'), fileExecOptions)
142
+ rmSync(join(process.cwd(), 'docs'), fileExecOptions)
143
+ }
144
+
145
+ /**
146
+ * @description Removes Husky files
147
+ */
148
+ function huskyCleanup() {
149
+ rmSync(join(process.cwd(), '.lintstagedrc.mjs'), fileExecOptions)
150
+ rmSync(join(process.cwd(), 'commitlint.config.js'), fileExecOptions)
151
+ rmSync(join(process.cwd(), '.husky'), fileExecOptions)
152
+ }
153
+
154
+ /**
155
+ * @description Removes the .install-files folder
156
+ */
157
+ function installFilesCleanup() {
158
+ console.log(`${chalk.bold.red('Removing')} installer files`)
159
+ rmSync(join(process.cwd(), '.install-files'), fileExecOptions)
160
+ }
161
+
162
+ /**
163
+ * @description Cleans up the files associated with removed packages
164
+ */
165
+ function packageFilesCleanup(subgraphSupport, typedocSupport, vocsSupport, huskySupport) {
166
+ const pkgPath = join(process.cwd(), 'package.json')
167
+ const pkgJson = JSON.parse(readFileSync(pkgPath, 'utf8'))
168
+
169
+ console.log(
170
+ `${chalk.bold.red('Removing')} files and scripts associated with uninstalled packages`,
171
+ )
172
+
173
+ // Remove everything subgraph-related
174
+ if (!subgraphSupport) {
175
+ subgraphCleanup()
176
+ pkgJson.scripts['subgraph-codegen'] = undefined
177
+ }
178
+
179
+ // Remove everything typedoc-related
180
+ if (!typedocSupport) {
181
+ typedocCleanup()
182
+ pkgJson.scripts['typedoc:build'] = undefined
183
+ }
184
+
185
+ // Remove everything vocs-related
186
+ if (!vocsSupport) {
187
+ vocsCleanup()
188
+ pkgJson.scripts['docs:build'] = undefined
189
+ pkgJson.scripts['docs:dev'] = undefined
190
+ pkgJson.scripts['docs:preview'] = undefined
191
+ }
192
+
193
+ // Remove everything husky-related
194
+ if (!huskySupport) {
195
+ huskyCleanup()
196
+ pkgJson.scripts['prepare'] = undefined
197
+ }
198
+
199
+ writeFileSync(pkgPath, `${JSON.stringify(pkgJson, null, 2)}\n`)
200
+ }
@@ -0,0 +1,145 @@
1
+ import { join } from 'node:path'
2
+ import readline from 'node:readline'
3
+ import chalk from 'chalk'
4
+ import { homeFolder } from './config.js'
5
+
6
+ /**
7
+ * @description Check if the project name is valid
8
+ */
9
+ export function checkProjectName(name) {
10
+ const error = !name
11
+ ? `
12
+ #################################################
13
+ # A directory name is mandatory. #
14
+ # #
15
+ # Letters (a–z, A–Z), numbers (0–9), #
16
+ # hyphens (-), and underscores (_) are allowed. #
17
+ #################################################`
18
+ : !/^[a-zA-Z0-9-_]+$/.test(name)
19
+ ? `
20
+ #################################################
21
+ # Invalid project name. #
22
+ # #
23
+ # Letters (a–z, A–Z), numbers (0–9), #
24
+ # hyphens (-), and underscores (_) are allowed. #
25
+ #################################################`
26
+ : ''
27
+
28
+ if (error) {
29
+ console.error(`${chalk.red.bold(error.trim())}`)
30
+ process.exit(1)
31
+ } else {
32
+ return name.replace(/[^a-zA-Z0-9-_]/g, '-')
33
+ }
34
+ }
35
+
36
+ /**
37
+ * @description Asks a question to the user
38
+ */
39
+ function askQuestion(query) {
40
+ const rl = readline.createInterface({
41
+ input: process.stdin,
42
+ output: process.stdout,
43
+ })
44
+
45
+ return new Promise((resolve) => {
46
+ rl.question(query, (answer) => {
47
+ rl.close()
48
+ resolve(answer)
49
+ })
50
+ })
51
+ }
52
+
53
+ /**
54
+ * @description Asks the user for setup options
55
+ * @returns {Promise<{demoSupport: boolean, subgraphSupport: boolean, typedocSupport: boolean, vocsSupport: boolean, commitHookPackagesSupport: boolean}>}
56
+ */
57
+ export async function installationSetup() {
58
+ const demoSupport =
59
+ (await askQuestion(`Keep the ${chalk.bold('home page demos')}? (Y/n) `)).toLowerCase() !== 'n'
60
+
61
+ const subgraphSupport =
62
+ (await askQuestion(`Keep ${chalk.bold('subgraph')} support? (Y/n) `)).toLowerCase() !== 'n'
63
+
64
+ const typedocSupport =
65
+ (
66
+ await askQuestion(
67
+ `Keep ${chalk.bold('Typedoc')} (converts TypeScript comments to HTML documentation) support? (Y/n) `,
68
+ )
69
+ ).toLowerCase() !== 'n'
70
+
71
+ const vocsSupport =
72
+ (
73
+ await askQuestion(
74
+ `Keep ${chalk.bold('Vocs')} (static markdown documentation generation) support? (Y/n) `,
75
+ )
76
+ ).toLowerCase() !== 'n'
77
+
78
+ const huskySupport =
79
+ (
80
+ await askQuestion(
81
+ `Keep ${chalk.bold('Husky')} (Git hooks) support? Note: removing this will also remove ${chalk.bold('lint-staged')} and ${chalk.bold('commitlint')} (Y/n) `,
82
+ )
83
+ ).toLowerCase() !== 'n'
84
+
85
+ return {
86
+ demoSupport,
87
+ subgraphSupport,
88
+ typedocSupport,
89
+ vocsSupport,
90
+ huskySupport,
91
+ }
92
+ }
93
+
94
+ /**
95
+ * @description Prints instructions for subgraph support
96
+ */
97
+ function subgraphInstructions() {
98
+ console.log(
99
+ `${chalk.yellow.bold('##################################################################################')}`,
100
+ )
101
+ console.log(
102
+ `${chalk.yellow.bold('# WARNING: Your project support subgraphs, before you continue you MUST: #')}`,
103
+ )
104
+ console.log(
105
+ `${chalk.yellow.bold('##################################################################################')}`,
106
+ )
107
+ console.log('')
108
+ console.log(
109
+ `1- Provide your own API key for the var ${chalk.bold('PUBLIC_SUBGRAPHS_API_KEY')} in ${chalk.italic('.env.local')}`,
110
+ )
111
+ console.log(
112
+ ` You can get one at ${chalk.bold.underline('https://thegraph.com/studio/apikeys/')}`,
113
+ )
114
+ console.log(
115
+ `2- Run ${chalk.bold('pnpm subgraph-codegen')} in your console from the project's folder`,
116
+ )
117
+ console.log('')
118
+ console.log('Only after you followed these steps you may proceed.')
119
+ console.log('\n---\n')
120
+ }
121
+
122
+ /**
123
+ * @description Prints post-install instructions
124
+ */
125
+ export function postInstallInstructions(subgraphSupport, projectName) {
126
+ console.log('To start development on your project:')
127
+ console.log('')
128
+ console.log('1- Move into the project directory')
129
+ console.log(chalk.cyan(`$ cd ${projectName}`))
130
+ console.log('')
131
+ console.log('2- Start the development server')
132
+ console.log(chalk.cyan('$ pnpm dev'))
133
+ console.log('')
134
+ console.log(
135
+ `You can edit the home page in ${chalk.bold(`${join(process.cwd(), homeFolder)}/index.tsx`)}`,
136
+ )
137
+ console.log('\n---\n')
138
+ console.log(`Check out ${chalk.bold('.env.local')} for more project configurations.`)
139
+ console.log(`Check out the docs at ${chalk.bold.underline('https://docs.dappbooster.dev/')}`)
140
+ console.log('\n---\n')
141
+
142
+ if (subgraphSupport) {
143
+ subgraphInstructions()
144
+ }
145
+ }
package/index.js CHANGED
@@ -1,91 +1,33 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { execSync } from "child_process";
4
- import { join } from "path";
5
- import { rmSync } from "fs";
6
- import chalk from "chalk";
7
-
8
- const repoUrl = "https://github.com/bootnodedev/dappbooster.git";
9
- const projectName = process.argv[2];
10
-
11
- if (!projectName || !/^[a-zA-Z0-9-_]+$/.test(projectName)) {
12
- console.error("Invalid directory name. Please enter a valid project name.");
13
- process.exit(1);
14
- }
15
-
16
- cloneRepo(projectName);
17
-
18
- function getLatestTag() {
19
- // Get all tags, sorted by version
20
- const tags = execSync("git tag -l --sort=-v:refname")
21
- .toString()
22
- .trim()
23
- .split("\n");
24
-
25
- // Return the first (latest) tag
26
- return tags[0];
27
- }
28
-
29
- function cloneRepo(projectName) {
30
- const sanitizedProjectName = projectName.replace(/[^a-zA-Z0-9-_]/g, "-");
31
- const projectDir = join(process.cwd(), sanitizedProjectName);
32
- const execOptions = {
33
- stdio: "pipe",
34
- shell: true,
35
- };
36
-
37
- try {
38
- console.log(`Cloning dAppBooster...`);
39
-
40
- // Clone the repository
41
- execSync(
42
- `git clone --depth 1 --no-checkout "${repoUrl}" "${projectDir}"`,
43
- execOptions
44
- );
45
-
46
- // Change to the project directory
47
- process.chdir(projectDir);
48
-
49
- // Fetch all tags
50
- execSync("git fetch --tags", execOptions);
51
-
52
- // Get the latest tag
53
- const latestTag = getLatestTag();
54
-
55
- if (!latestTag) {
56
- throw new Error("No tags found in the repository");
57
- }
58
-
59
- // Checkout the latest tag
60
- execSync(`git checkout "${latestTag}"`, execOptions);
61
-
62
- // Remove the .git directory
63
- rmSync(join(projectDir, ".git"), { recursive: true, force: true });
64
-
65
- // Initialize a new git repository
66
- execSync("git init", execOptions);
67
-
68
- console.log(`dAppBooster repository cloned in ${chalk.bold(projectDir)}`);
69
- console.log(`Latest version: ${chalk.bold(latestTag)}`);
70
- console.log(`
71
- ${chalk.green.bold(
72
- "You can now start your project with the following commands:"
73
- )}
74
-
75
- ${chalk.blue("# Change to the project directory")}
76
- $ ${chalk.cyan(`cd ${sanitizedProjectName}`)}
77
-
78
- ${chalk.blue("# Install dependencies")}
79
- $ ${chalk.cyan("pnpm install")}
80
-
81
- ${chalk.blue("# Copy the example environment file")}
82
- $ ${chalk.cyan("cp .env.example .env.local")}
83
-
84
- ${chalk.blue("# Start the development server")}
85
- $ ${chalk.cyan("pnpm dev")}
86
- `);
87
- } catch (error) {
88
- console.error(`${chalk.bold.red("An error occurred:")}`, error.message);
89
- process.exit(1);
90
- }
3
+ import { createEnvFile, installPackages } from './import/install.js'
4
+ import { cloneRepo } from './import/git.js'
5
+ import {
6
+ checkProjectName,
7
+ installationSetup,
8
+ postInstallInstructions,
9
+ } from './import/user-prompts.js'
10
+
11
+ main().then(() => console.log('\nšŸ‘»\n'))
12
+
13
+ /**
14
+ * @description Main entry point
15
+ */
16
+ async function main() {
17
+ // Check if the project name is valid
18
+ const projectName = checkProjectName(process.argv[2])
19
+
20
+ // Clone, create .env.local file
21
+ cloneRepo(projectName)
22
+ createEnvFile(projectName)
23
+
24
+ // Ask setup questions
25
+ const { demoSupport, subgraphSupport, typedocSupport, vocsSupport, huskySupport } =
26
+ await installationSetup()
27
+
28
+ // Install the required packages
29
+ installPackages(demoSupport, subgraphSupport, typedocSupport, vocsSupport, huskySupport)
30
+
31
+ // Tell the user what to do after installation is finished
32
+ postInstallInstructions(subgraphSupport, projectName)
91
33
  }
package/package.json CHANGED
@@ -1,15 +1,17 @@
1
1
  {
2
2
  "name": "dappbooster",
3
- "version": "0.3.3",
3
+ "author": "bootnodedev",
4
+ "version": "2.0.0",
4
5
  "description": "Script to easily start your project with dAppBooster",
5
6
  "main": "index.js",
7
+ "license": "MIT",
8
+ "engines": {
9
+ "node": ">=20.0.0"
10
+ },
6
11
  "bin": {
7
12
  "dappbooster": "index.js"
8
13
  },
9
14
  "type": "module",
10
- "scripts": {
11
- "test": "echo \"Error: no test specified\" && exit 1"
12
- },
13
15
  "dependencies": {
14
16
  "chalk": "^5.3.0"
15
17
  },
@@ -20,9 +22,7 @@
20
22
  "installer",
21
23
  "dapp"
22
24
  ],
23
- "author": "bootnodedev",
24
- "license": "MIT",
25
- "engines": {
26
- "node": ">=20.0.0"
25
+ "devDependencies": {
26
+ "prettier": "^3.5.3"
27
27
  }
28
28
  }