create-turbo-kit 1.1.0 → 1.2.1
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/dist/{chunk-SYNNS7BI.js → chunk-SGKVPRAI.js} +59 -6
- package/dist/chunk-SGKVPRAI.js.map +1 -0
- package/dist/cli.js +4 -1
- package/dist/cli.js.map +1 -1
- package/dist/helpers/transform.d.ts +16 -1
- package/dist/helpers/transform.js +1 -1
- package/package.json +1 -1
- package/src/cli.ts +3 -0
- package/src/helpers/transform.ts +65 -2
- package/dist/chunk-SYNNS7BI.js.map +0 -1
|
@@ -8,17 +8,32 @@ var DOCKER_CONTAINERS = {
|
|
|
8
8
|
postgres: {
|
|
9
9
|
label: "PostgreSQL 16 (Database)",
|
|
10
10
|
services: ["postgres"],
|
|
11
|
-
volumes: ["postgres_data"]
|
|
11
|
+
volumes: ["postgres_data"],
|
|
12
|
+
dependsOn: []
|
|
13
|
+
},
|
|
14
|
+
pgadmin: {
|
|
15
|
+
label: `pgAdmin 4.9 (Database management) [Depends on PostgreSQL]`,
|
|
16
|
+
services: ["pgadmin"],
|
|
17
|
+
volumes: [],
|
|
18
|
+
dependsOn: ["postgres"]
|
|
19
|
+
},
|
|
20
|
+
redis: {
|
|
21
|
+
label: "Redis (Caching)",
|
|
22
|
+
services: ["redis"],
|
|
23
|
+
volumes: [],
|
|
24
|
+
dependsOn: []
|
|
12
25
|
},
|
|
13
26
|
mailpit: {
|
|
14
27
|
label: "Mailpit (Email testing)",
|
|
15
28
|
services: ["mailpit"],
|
|
16
|
-
volumes: []
|
|
29
|
+
volumes: [],
|
|
30
|
+
dependsOn: []
|
|
17
31
|
},
|
|
18
32
|
minio: {
|
|
19
33
|
label: "MinIO (S3-compatible storage)",
|
|
20
34
|
services: ["minio", "minio-create-bucket"],
|
|
21
|
-
volumes: ["minio_data"]
|
|
35
|
+
volumes: ["minio_data"],
|
|
36
|
+
dependsOn: []
|
|
22
37
|
}
|
|
23
38
|
};
|
|
24
39
|
async function replaceScope(projectDir, newScope) {
|
|
@@ -78,6 +93,12 @@ async function deleteDockerCompose(projectDir) {
|
|
|
78
93
|
const dockerComposePath = path.join(projectDir, "docker-compose.yml");
|
|
79
94
|
if (await fs.pathExists(dockerComposePath)) {
|
|
80
95
|
await fs.remove(dockerComposePath);
|
|
96
|
+
s.message(`Removed ${color.cyan(dockerComposePath)}`);
|
|
97
|
+
}
|
|
98
|
+
const dockerDir = path.join(projectDir, "docker");
|
|
99
|
+
if (await fs.pathExists(dockerDir)) {
|
|
100
|
+
await fs.remove(dockerDir);
|
|
101
|
+
s.message(`Removed ${color.cyan(dockerDir)}`);
|
|
81
102
|
}
|
|
82
103
|
s.stop("Removed Docker Compose setup");
|
|
83
104
|
} catch (error) {
|
|
@@ -85,6 +106,23 @@ async function deleteDockerCompose(projectDir) {
|
|
|
85
106
|
throw error;
|
|
86
107
|
}
|
|
87
108
|
}
|
|
109
|
+
function resolveContainerDependencies(selectedContainers) {
|
|
110
|
+
const resolved = new Set(selectedContainers);
|
|
111
|
+
const queue = [...selectedContainers];
|
|
112
|
+
while (queue.length > 0) {
|
|
113
|
+
const current = queue.shift();
|
|
114
|
+
const config = DOCKER_CONTAINERS[current];
|
|
115
|
+
if (config && config.dependsOn) {
|
|
116
|
+
for (const dep of config.dependsOn) {
|
|
117
|
+
if (!resolved.has(dep)) {
|
|
118
|
+
resolved.add(dep);
|
|
119
|
+
queue.push(dep);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return Array.from(resolved);
|
|
125
|
+
}
|
|
88
126
|
async function configureDockerCompose(projectDir, selectedContainers) {
|
|
89
127
|
const s = spinner();
|
|
90
128
|
s.start("Configuring Docker Compose...");
|
|
@@ -94,20 +132,35 @@ async function configureDockerCompose(projectDir, selectedContainers) {
|
|
|
94
132
|
s.stop("Docker Compose file not found");
|
|
95
133
|
return;
|
|
96
134
|
}
|
|
135
|
+
const resolvedContainers = resolveContainerDependencies(selectedContainers);
|
|
136
|
+
const addedDependencies = resolvedContainers.filter((c) => !selectedContainers.includes(c));
|
|
137
|
+
if (addedDependencies.length > 0) {
|
|
138
|
+
s.message(`Auto-including dependencies: ${color.cyan(addedDependencies.join(", "))}`);
|
|
139
|
+
}
|
|
97
140
|
let content = await fs.readFile(dockerComposePath, "utf8");
|
|
98
141
|
const allContainers = Object.keys(DOCKER_CONTAINERS);
|
|
99
|
-
const containersToRemove = allContainers.filter((c) => !
|
|
142
|
+
const containersToRemove = allContainers.filter((c) => !resolvedContainers.includes(c));
|
|
100
143
|
for (const container of containersToRemove) {
|
|
101
144
|
const containerRegex = new RegExp(
|
|
102
145
|
` # -- ${container} --\\n[\\s\\S]*? # // ${container} //\\n`,
|
|
103
146
|
"g"
|
|
104
147
|
);
|
|
105
148
|
content = content.replace(containerRegex, "");
|
|
149
|
+
const dockerDirPath = path.join(projectDir, "docker", container);
|
|
150
|
+
if (await fs.pathExists(dockerDirPath)) {
|
|
151
|
+
await fs.remove(dockerDirPath);
|
|
152
|
+
s.message(`Removed ${color.cyan(dockerDirPath)}`);
|
|
153
|
+
}
|
|
106
154
|
}
|
|
107
155
|
content = content.replace(/ # -- \w+ --\n/g, "");
|
|
108
156
|
content = content.replace(/ # \/\/ \w+ \/\/\n/g, "");
|
|
109
157
|
await fs.writeFile(dockerComposePath, content);
|
|
110
|
-
|
|
158
|
+
const dockerDir = path.join(projectDir, "docker");
|
|
159
|
+
if (await fs.pathExists(dockerDir) && (await fs.readdir(dockerDir)).length === 0) {
|
|
160
|
+
await fs.remove(dockerDir);
|
|
161
|
+
s.message(`Removed ${color.cyan(dockerDir)} ${color.gray("(because it was empty)")}`);
|
|
162
|
+
}
|
|
163
|
+
s.stop(`Configured Docker Compose with ${color.cyan(resolvedContainers.length)} container(s)`);
|
|
111
164
|
} catch (error) {
|
|
112
165
|
s.stop("Failed to configure Docker Compose");
|
|
113
166
|
throw error;
|
|
@@ -121,4 +174,4 @@ export {
|
|
|
121
174
|
deleteDockerCompose,
|
|
122
175
|
configureDockerCompose
|
|
123
176
|
};
|
|
124
|
-
//# sourceMappingURL=chunk-
|
|
177
|
+
//# sourceMappingURL=chunk-SGKVPRAI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/helpers/transform.ts"],"sourcesContent":["import fg from 'fast-glob';\r\nimport fs from 'fs-extra';\r\nimport path from 'path';\r\nimport { spinner } from '@clack/prompts';\r\nimport color from 'picocolors';\r\n\r\nconst DOCKER_CONTAINERS = {\r\n postgres: {\r\n label: 'PostgreSQL 16 (Database)',\r\n services: ['postgres'],\r\n volumes: ['postgres_data'],\r\n dependsOn: [], \r\n },\r\n pgadmin: {\r\n label: `pgAdmin 4.9 (Database management) [Depends on PostgreSQL]`,\r\n services: ['pgadmin'],\r\n volumes: [],\r\n dependsOn: ['postgres'],\r\n },\r\n redis: {\r\n label: 'Redis (Caching)',\r\n services: ['redis'],\r\n volumes: [],\r\n dependsOn: [],\r\n },\r\n mailpit: {\r\n label: 'Mailpit (Email testing)',\r\n services: ['mailpit'],\r\n volumes: [],\r\n dependsOn: [],\r\n },\r\n minio: {\r\n label: 'MinIO (S3-compatible storage)',\r\n services: ['minio', 'minio-create-bucket'],\r\n volumes: ['minio_data'],\r\n dependsOn: [],\r\n },\r\n} as const;\r\n\r\nexport type DockerContainer = keyof typeof DOCKER_CONTAINERS;\r\n\r\nexport async function replaceScope(projectDir: string, newScope: string) {\r\n const s = spinner();\r\n s.start(`Replacing scope with ${color.cyan(newScope)}...`);\r\n\r\n try {\r\n const files = await fg('**/*', {\r\n cwd: projectDir,\r\n ignore: [\r\n '**/.git/**',\r\n '**/node_modules/**',\r\n '**/.turbo/**',\r\n '**/dist/**',\r\n '**/.next/**',\r\n '**/pnpm-lock.yaml',\r\n '**/yarn.lock',\r\n '**/package-lock.json',\r\n '**/bun.lockb',\r\n ],\r\n absolute: true,\r\n });\r\n\r\n await Promise.all(\r\n files.map(async (file) => {\r\n try {\r\n const content = await fs.readFile(file, 'utf8');\r\n if (content.includes('@acme')) {\r\n const newContent = content.replace(/@acme/g, newScope);\r\n await fs.writeFile(file, newContent);\r\n }\r\n } catch (e) {\r\n }\r\n })\r\n );\r\n \r\n s.stop(`Replaced scope with ${color.cyan(newScope)}`);\r\n } catch (error) {\r\n s.stop('Failed to replace scope');\r\n throw error;\r\n }\r\n}\r\n\r\nexport async function setupEnv(projectDir: string) {\r\n const envExample = path.join(projectDir, '.env.example');\r\n const envDest = path.join(projectDir, '.env');\r\n\r\n if (await fs.pathExists(envExample)) {\r\n await fs.copy(envExample, envDest);\r\n }\r\n}\r\n\r\nexport function getDockerContainers() {\r\n return Object.entries(DOCKER_CONTAINERS).map(([value, config]) => ({\r\n value,\r\n label: config.label,\r\n }));\r\n}\r\n\r\nexport async function deleteDockerCompose(projectDir: string) {\r\n const s = spinner();\r\n s.start('Removing Docker Compose setup...');\r\n\r\n try {\r\n const dockerComposePath = path.join(projectDir, 'docker-compose.yml');\r\n if (await fs.pathExists(dockerComposePath)) {\r\n await fs.remove(dockerComposePath);\r\n s.message(`Removed ${color.cyan(dockerComposePath)}`);\r\n }\r\n const dockerDir = path.join(projectDir, 'docker');\r\n if (await fs.pathExists(dockerDir)) {\r\n await fs.remove(dockerDir);\r\n s.message(`Removed ${color.cyan(dockerDir)}`);\r\n }\r\n s.stop('Removed Docker Compose setup');\r\n } catch (error) {\r\n s.stop('Failed to remove Docker Compose setup');\r\n throw error;\r\n }\r\n}\r\n\r\nfunction resolveContainerDependencies(selectedContainers: string[]): string[] {\r\n const resolved = new Set<string>(selectedContainers);\r\n const queue = [...selectedContainers];\r\n\r\n while (queue.length > 0) {\r\n const current = queue.shift()!;\r\n const config = DOCKER_CONTAINERS[current as DockerContainer];\r\n \r\n if (config && config.dependsOn) {\r\n for (const dep of config.dependsOn) {\r\n if (!resolved.has(dep)) {\r\n resolved.add(dep);\r\n queue.push(dep);\r\n }\r\n }\r\n }\r\n }\r\n\r\n return Array.from(resolved);\r\n}\r\n\r\nexport async function configureDockerCompose(projectDir: string, selectedContainers: string[]) {\r\n const s = spinner();\r\n s.start('Configuring Docker Compose...');\r\n\r\n try {\r\n const dockerComposePath = path.join(projectDir, 'docker-compose.yml');\r\n \r\n if (!(await fs.pathExists(dockerComposePath))) {\r\n s.stop('Docker Compose file not found');\r\n return;\r\n }\r\n\r\n const resolvedContainers = resolveContainerDependencies(selectedContainers);\r\n const addedDependencies = resolvedContainers.filter(c => !selectedContainers.includes(c));\r\n \r\n if (addedDependencies.length > 0) {\r\n s.message(`Auto-including dependencies: ${color.cyan(addedDependencies.join(', '))}`);\r\n }\r\n\r\n let content = await fs.readFile(dockerComposePath, 'utf8');\r\n\r\n const allContainers = Object.keys(DOCKER_CONTAINERS) as DockerContainer[];\r\n const containersToRemove = allContainers.filter(c => !resolvedContainers.includes(c));\r\n\r\n for (const container of containersToRemove) {\r\n const containerRegex = new RegExp(\r\n ` # -- ${container} --\\\\n[\\\\s\\\\S]*? # // ${container} //\\\\n`,\r\n 'g'\r\n );\r\n content = content.replace(containerRegex, '');\r\n\r\n // delete `./docker/<container>/`\r\n const dockerDirPath = path.join(projectDir, 'docker', container);\r\n if (await fs.pathExists(dockerDirPath)) {\r\n await fs.remove(dockerDirPath);\r\n s.message(`Removed ${color.cyan(dockerDirPath)}`);\r\n }\r\n }\r\n\r\n content = content.replace(/ # -- \\w+ --\\n/g, '');\r\n content = content.replace(/ # \\/\\/ \\w+ \\/\\/\\n/g, '');\r\n\r\n await fs.writeFile(dockerComposePath, content);\r\n\r\n // check if `./docker/` is empty\r\n const dockerDir = path.join(projectDir, 'docker');\r\n if (await fs.pathExists(dockerDir) && (await fs.readdir(dockerDir)).length === 0) {\r\n await fs.remove(dockerDir);\r\n s.message(`Removed ${color.cyan(dockerDir)} ${color.gray('(because it was empty)')}`);\r\n }\r\n \r\n s.stop(`Configured Docker Compose with ${color.cyan(resolvedContainers.length)} container(s)`);\r\n } catch (error) {\r\n s.stop('Failed to configure Docker Compose');\r\n throw error;\r\n }\r\n}\r\n\r\n"],"mappings":"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","names":[]}
|
package/dist/cli.js
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
getDockerContainers,
|
|
12
12
|
replaceScope,
|
|
13
13
|
setupEnv
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-SGKVPRAI.js";
|
|
15
15
|
import "./chunk-EYEU3RGM.js";
|
|
16
16
|
|
|
17
17
|
// src/cli.ts
|
|
@@ -152,6 +152,9 @@ Your import statements will look like this: ${importStatement}`,
|
|
|
152
152
|
if (!shouldInstall) {
|
|
153
153
|
console.log(color.cyan(` ${packageManager} install`));
|
|
154
154
|
}
|
|
155
|
+
if (wantsDocker) {
|
|
156
|
+
console.log(color.cyan(` docker compose up -d`));
|
|
157
|
+
}
|
|
155
158
|
console.log(color.cyan(` ${packageManager} run dev`));
|
|
156
159
|
console.log();
|
|
157
160
|
console.log(color.greenBright("Happy Hacking!"));
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { intro, outro, text, select, isCancel, cancel, confirm, multiselect } from '@clack/prompts';\r\nimport { Command } from 'commander';\r\nimport color from 'picocolors';\r\nimport fs from 'fs-extra';\r\nimport path from 'path';\r\nimport { replaceScope, setupEnv, getDockerContainers, configureDockerCompose, deleteDockerCompose } from './helpers/transform.js';\r\nimport { installDependencies, initializeGit } from './helpers/install.js';\r\nimport { type PackageManager } from './utils/package-manager.js';\r\nimport { scaffoldProject } from './helpers/scaffold.js';\r\n\r\nasync function main() {\r\n const program = new Command();\r\n \r\n program\r\n .name('create-turbo-kit')\r\n .description('Initialize a custom turborepo template')\r\n .argument('[project-name]', 'Name of the project directory')\r\n .parse(process.argv);\r\n\r\n const args = program.args;\r\n let projectName = args[0];\r\n\r\n console.log();\r\n intro(color.bgCyan(color.black(' Create Turbo Kit ')));\r\n\r\n if (!projectName) {\r\n const pName = await text({\r\n message: 'What is your project named?',\r\n placeholder: 'my-turbo-app',\r\n validate: (value) => {\r\n if (!value) return 'Please enter a name.';\r\n if (/[^a-zA-Z0-9-_]/.test(value)) return 'Project name can only contain letters, numbers, dashes and underscores.';\r\n const projectDir = path.resolve(process.cwd(), value);\r\n if (fs.pathExistsSync(projectDir)) {\r\n return 'Project name already taken.';\r\n }\r\n return undefined;\r\n },\r\n });\r\n\r\n if (isCancel(pName)) {\r\n cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n projectName = pName as string;\r\n }\r\n\r\n const projectDir = path.resolve(process.cwd(), projectName);\r\n\r\n if (await fs.pathExists(projectDir)) {\r\n const shouldOverwrite = await confirm({\r\n message: `Directory ${projectName} already exists. Do you want to overwrite it?`,\r\n initialValue: false,\r\n });\r\n\r\n if (isCancel(shouldOverwrite) || !shouldOverwrite) {\r\n cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n \r\n await fs.remove(projectDir);\r\n }\r\n\r\n const packageManager = await select({\r\n message: 'Which package manager do you want to use?',\r\n options: [\r\n { value: 'pnpm', label: 'pnpm' },\r\n { value: 'npm', label: 'npm' },\r\n { value: 'yarn', label: 'yarn' },\r\n { value: 'bun', label: 'bun' },\r\n ],\r\n });\r\n\r\n if (isCancel(packageManager)) {\r\n cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n const getScope = async (): Promise<string> => {\r\n const scope = await text({\r\n message: 'What is your package scope?',\r\n placeholder: '@my-org',\r\n validate: (value) => {\r\n if (!value) return 'Please enter a scope.';\r\n },\r\n });\r\n \r\n if (isCancel(scope)) {\r\n cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n const check = [\"@\", \"~\", \"$\", \"#\", \"!\"];\r\n if (!check.includes(scope[0] as string)) {\r\n // ask the user to confirm this is the correct scope\r\n const importStatement = `${color.magenta(\"import\")} ${color.yellow(\"{\")} ${color.cyan(\"example\")} ${color.yellow(\"}\")} ${color.magenta(\"from\")} ${color.cyan(`\"${scope}/example\"`)}`;\r\n const confirmScope = await confirm({\r\n message: `Is ${color.cyan(scope)} the correct scope?\\nYour import statements will look like this: ${importStatement}`,\r\n initialValue: true,\r\n });\r\n if (isCancel(confirmScope) || !confirmScope) {\r\n return await getScope();\r\n }\r\n }\r\n\r\n return scope as string;\r\n }\r\n const scope = await getScope();\r\n\r\n try {\r\n await scaffoldProject({\r\n projectName,\r\n packageManager: packageManager as PackageManager,\r\n });\r\n\r\n const wantsDocker = await confirm({\r\n message: 'Do you want to set up a local Docker Compose dev environment?',\r\n initialValue: true,\r\n });\r\n\r\n if (isCancel(wantsDocker)) {\r\n cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n if (wantsDocker) {\r\n const dockerContainers = getDockerContainers();\r\n const containers = await multiselect({\r\n message: 'Which containers do you want to include?',\r\n options: dockerContainers,\r\n initialValues: dockerContainers.map((container) => container.value),\r\n required: false,\r\n });\r\n\r\n if (isCancel(containers)) {\r\n cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n if (Array.isArray(containers) && containers.length > 0) {\r\n await configureDockerCompose(projectDir, containers as string[]);\r\n } else {\r\n await deleteDockerCompose(projectDir);\r\n }\r\n } else {\r\n await deleteDockerCompose(projectDir);\r\n }\r\n\r\n const shouldInstall = await confirm({\r\n message: 'Do you want to install dependencies now?',\r\n initialValue: true,\r\n });\r\n\r\n if (isCancel(shouldInstall)) {\r\n cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n await replaceScope(projectDir, scope as string);\r\n await setupEnv(projectDir);\r\n \r\n if (shouldInstall) {\r\n await installDependencies(projectDir, packageManager as PackageManager);\r\n }\r\n\r\n await initializeGit(projectDir);\r\n\r\n outro(color.green('Project initialized successfully!'));\r\n \r\n console.log(`To get started:`);\r\n console.log(color.cyan(` cd ${projectName}`));\r\n if (!shouldInstall) {\r\n console.log(color.cyan(` ${packageManager} install`));\r\n }\r\n console.log(color.cyan(` ${packageManager} run dev`));\r\n \r\n console.log();\r\n console.log(color.greenBright(\"Happy Hacking!\"))\r\n } catch (error) {\r\n console.error(color.red('An error occurred:'), error);\r\n process.exit(1);\r\n }\r\n}\r\n\r\nmain().catch(console.error);\r\n"],"mappings":"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","names":["projectDir","scope"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { intro, outro, text, select, isCancel, cancel, confirm, multiselect } from '@clack/prompts';\r\nimport { Command } from 'commander';\r\nimport color from 'picocolors';\r\nimport fs from 'fs-extra';\r\nimport path from 'path';\r\nimport { replaceScope, setupEnv, getDockerContainers, configureDockerCompose, deleteDockerCompose } from './helpers/transform.js';\r\nimport { installDependencies, initializeGit } from './helpers/install.js';\r\nimport { type PackageManager } from './utils/package-manager.js';\r\nimport { scaffoldProject } from './helpers/scaffold.js';\r\n\r\nasync function main() {\r\n const program = new Command();\r\n \r\n program\r\n .name('create-turbo-kit')\r\n .description('Initialize a custom turborepo template')\r\n .argument('[project-name]', 'Name of the project directory')\r\n .parse(process.argv);\r\n\r\n const args = program.args;\r\n let projectName = args[0];\r\n\r\n console.log();\r\n intro(color.bgCyan(color.black(' Create Turbo Kit ')));\r\n\r\n if (!projectName) {\r\n const pName = await text({\r\n message: 'What is your project named?',\r\n placeholder: 'my-turbo-app',\r\n validate: (value) => {\r\n if (!value) return 'Please enter a name.';\r\n if (/[^a-zA-Z0-9-_]/.test(value)) return 'Project name can only contain letters, numbers, dashes and underscores.';\r\n const projectDir = path.resolve(process.cwd(), value);\r\n if (fs.pathExistsSync(projectDir)) {\r\n return 'Project name already taken.';\r\n }\r\n return undefined;\r\n },\r\n });\r\n\r\n if (isCancel(pName)) {\r\n cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n projectName = pName as string;\r\n }\r\n\r\n const projectDir = path.resolve(process.cwd(), projectName);\r\n\r\n if (await fs.pathExists(projectDir)) {\r\n const shouldOverwrite = await confirm({\r\n message: `Directory ${projectName} already exists. Do you want to overwrite it?`,\r\n initialValue: false,\r\n });\r\n\r\n if (isCancel(shouldOverwrite) || !shouldOverwrite) {\r\n cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n \r\n await fs.remove(projectDir);\r\n }\r\n\r\n const packageManager = await select({\r\n message: 'Which package manager do you want to use?',\r\n options: [\r\n { value: 'pnpm', label: 'pnpm' },\r\n { value: 'npm', label: 'npm' },\r\n { value: 'yarn', label: 'yarn' },\r\n { value: 'bun', label: 'bun' },\r\n ],\r\n });\r\n\r\n if (isCancel(packageManager)) {\r\n cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n const getScope = async (): Promise<string> => {\r\n const scope = await text({\r\n message: 'What is your package scope?',\r\n placeholder: '@my-org',\r\n validate: (value) => {\r\n if (!value) return 'Please enter a scope.';\r\n },\r\n });\r\n \r\n if (isCancel(scope)) {\r\n cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n const check = [\"@\", \"~\", \"$\", \"#\", \"!\"];\r\n if (!check.includes(scope[0] as string)) {\r\n // ask the user to confirm this is the correct scope\r\n const importStatement = `${color.magenta(\"import\")} ${color.yellow(\"{\")} ${color.cyan(\"example\")} ${color.yellow(\"}\")} ${color.magenta(\"from\")} ${color.cyan(`\"${scope}/example\"`)}`;\r\n const confirmScope = await confirm({\r\n message: `Is ${color.cyan(scope)} the correct scope?\\nYour import statements will look like this: ${importStatement}`,\r\n initialValue: true,\r\n });\r\n if (isCancel(confirmScope) || !confirmScope) {\r\n return await getScope();\r\n }\r\n }\r\n\r\n return scope as string;\r\n }\r\n const scope = await getScope();\r\n\r\n try {\r\n await scaffoldProject({\r\n projectName,\r\n packageManager: packageManager as PackageManager,\r\n });\r\n\r\n const wantsDocker = await confirm({\r\n message: 'Do you want to set up a local Docker Compose dev environment?',\r\n initialValue: true,\r\n });\r\n\r\n if (isCancel(wantsDocker)) {\r\n cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n if (wantsDocker) {\r\n const dockerContainers = getDockerContainers();\r\n const containers = await multiselect({\r\n message: 'Which containers do you want to include?',\r\n options: dockerContainers,\r\n initialValues: dockerContainers.map((container) => container.value),\r\n required: false,\r\n });\r\n\r\n if (isCancel(containers)) {\r\n cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n if (Array.isArray(containers) && containers.length > 0) {\r\n await configureDockerCompose(projectDir, containers as string[]);\r\n } else {\r\n await deleteDockerCompose(projectDir);\r\n }\r\n } else {\r\n await deleteDockerCompose(projectDir);\r\n }\r\n\r\n const shouldInstall = await confirm({\r\n message: 'Do you want to install dependencies now?',\r\n initialValue: true,\r\n });\r\n\r\n if (isCancel(shouldInstall)) {\r\n cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n await replaceScope(projectDir, scope as string);\r\n await setupEnv(projectDir);\r\n \r\n if (shouldInstall) {\r\n await installDependencies(projectDir, packageManager as PackageManager);\r\n }\r\n\r\n await initializeGit(projectDir);\r\n\r\n outro(color.green('Project initialized successfully!'));\r\n \r\n console.log(`To get started:`);\r\n console.log(color.cyan(` cd ${projectName}`));\r\n if (!shouldInstall) {\r\n console.log(color.cyan(` ${packageManager} install`));\r\n }\r\n if (wantsDocker) {\r\n console.log(color.cyan(` docker compose up -d`));\r\n }\r\n console.log(color.cyan(` ${packageManager} run dev`));\r\n \r\n console.log();\r\n console.log(color.greenBright(\"Happy Hacking!\"))\r\n } catch (error) {\r\n console.error(color.red('An error occurred:'), error);\r\n process.exit(1);\r\n }\r\n}\r\n\r\nmain().catch(console.error);\r\n"],"mappings":"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","names":["projectDir","scope"]}
|
|
@@ -3,16 +3,31 @@ declare const DOCKER_CONTAINERS: {
|
|
|
3
3
|
readonly label: "PostgreSQL 16 (Database)";
|
|
4
4
|
readonly services: readonly ["postgres"];
|
|
5
5
|
readonly volumes: readonly ["postgres_data"];
|
|
6
|
+
readonly dependsOn: readonly [];
|
|
7
|
+
};
|
|
8
|
+
readonly pgadmin: {
|
|
9
|
+
readonly label: "pgAdmin 4.9 (Database management) [Depends on PostgreSQL]";
|
|
10
|
+
readonly services: readonly ["pgadmin"];
|
|
11
|
+
readonly volumes: readonly [];
|
|
12
|
+
readonly dependsOn: readonly ["postgres"];
|
|
13
|
+
};
|
|
14
|
+
readonly redis: {
|
|
15
|
+
readonly label: "Redis (Caching)";
|
|
16
|
+
readonly services: readonly ["redis"];
|
|
17
|
+
readonly volumes: readonly [];
|
|
18
|
+
readonly dependsOn: readonly [];
|
|
6
19
|
};
|
|
7
20
|
readonly mailpit: {
|
|
8
21
|
readonly label: "Mailpit (Email testing)";
|
|
9
22
|
readonly services: readonly ["mailpit"];
|
|
10
23
|
readonly volumes: readonly [];
|
|
24
|
+
readonly dependsOn: readonly [];
|
|
11
25
|
};
|
|
12
26
|
readonly minio: {
|
|
13
27
|
readonly label: "MinIO (S3-compatible storage)";
|
|
14
28
|
readonly services: readonly ["minio", "minio-create-bucket"];
|
|
15
29
|
readonly volumes: readonly ["minio_data"];
|
|
30
|
+
readonly dependsOn: readonly [];
|
|
16
31
|
};
|
|
17
32
|
};
|
|
18
33
|
type DockerContainer = keyof typeof DOCKER_CONTAINERS;
|
|
@@ -20,7 +35,7 @@ declare function replaceScope(projectDir: string, newScope: string): Promise<voi
|
|
|
20
35
|
declare function setupEnv(projectDir: string): Promise<void>;
|
|
21
36
|
declare function getDockerContainers(): {
|
|
22
37
|
value: string;
|
|
23
|
-
label: "PostgreSQL 16 (Database)" | "Mailpit (Email testing)" | "MinIO (S3-compatible storage)";
|
|
38
|
+
label: "PostgreSQL 16 (Database)" | "pgAdmin 4.9 (Database management) [Depends on PostgreSQL]" | "Redis (Caching)" | "Mailpit (Email testing)" | "MinIO (S3-compatible storage)";
|
|
24
39
|
}[];
|
|
25
40
|
declare function deleteDockerCompose(projectDir: string): Promise<void>;
|
|
26
41
|
declare function configureDockerCompose(projectDir: string, selectedContainers: string[]): Promise<void>;
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -172,6 +172,9 @@ async function main() {
|
|
|
172
172
|
if (!shouldInstall) {
|
|
173
173
|
console.log(color.cyan(` ${packageManager} install`));
|
|
174
174
|
}
|
|
175
|
+
if (wantsDocker) {
|
|
176
|
+
console.log(color.cyan(` docker compose up -d`));
|
|
177
|
+
}
|
|
175
178
|
console.log(color.cyan(` ${packageManager} run dev`));
|
|
176
179
|
|
|
177
180
|
console.log();
|
package/src/helpers/transform.ts
CHANGED
|
@@ -9,16 +9,31 @@ const DOCKER_CONTAINERS = {
|
|
|
9
9
|
label: 'PostgreSQL 16 (Database)',
|
|
10
10
|
services: ['postgres'],
|
|
11
11
|
volumes: ['postgres_data'],
|
|
12
|
+
dependsOn: [],
|
|
13
|
+
},
|
|
14
|
+
pgadmin: {
|
|
15
|
+
label: `pgAdmin 4.9 (Database management) [Depends on PostgreSQL]`,
|
|
16
|
+
services: ['pgadmin'],
|
|
17
|
+
volumes: [],
|
|
18
|
+
dependsOn: ['postgres'],
|
|
19
|
+
},
|
|
20
|
+
redis: {
|
|
21
|
+
label: 'Redis (Caching)',
|
|
22
|
+
services: ['redis'],
|
|
23
|
+
volumes: [],
|
|
24
|
+
dependsOn: [],
|
|
12
25
|
},
|
|
13
26
|
mailpit: {
|
|
14
27
|
label: 'Mailpit (Email testing)',
|
|
15
28
|
services: ['mailpit'],
|
|
16
29
|
volumes: [],
|
|
30
|
+
dependsOn: [],
|
|
17
31
|
},
|
|
18
32
|
minio: {
|
|
19
33
|
label: 'MinIO (S3-compatible storage)',
|
|
20
34
|
services: ['minio', 'minio-create-bucket'],
|
|
21
35
|
volumes: ['minio_data'],
|
|
36
|
+
dependsOn: [],
|
|
22
37
|
},
|
|
23
38
|
} as const;
|
|
24
39
|
|
|
@@ -89,6 +104,12 @@ export async function deleteDockerCompose(projectDir: string) {
|
|
|
89
104
|
const dockerComposePath = path.join(projectDir, 'docker-compose.yml');
|
|
90
105
|
if (await fs.pathExists(dockerComposePath)) {
|
|
91
106
|
await fs.remove(dockerComposePath);
|
|
107
|
+
s.message(`Removed ${color.cyan(dockerComposePath)}`);
|
|
108
|
+
}
|
|
109
|
+
const dockerDir = path.join(projectDir, 'docker');
|
|
110
|
+
if (await fs.pathExists(dockerDir)) {
|
|
111
|
+
await fs.remove(dockerDir);
|
|
112
|
+
s.message(`Removed ${color.cyan(dockerDir)}`);
|
|
92
113
|
}
|
|
93
114
|
s.stop('Removed Docker Compose setup');
|
|
94
115
|
} catch (error) {
|
|
@@ -97,6 +118,27 @@ export async function deleteDockerCompose(projectDir: string) {
|
|
|
97
118
|
}
|
|
98
119
|
}
|
|
99
120
|
|
|
121
|
+
function resolveContainerDependencies(selectedContainers: string[]): string[] {
|
|
122
|
+
const resolved = new Set<string>(selectedContainers);
|
|
123
|
+
const queue = [...selectedContainers];
|
|
124
|
+
|
|
125
|
+
while (queue.length > 0) {
|
|
126
|
+
const current = queue.shift()!;
|
|
127
|
+
const config = DOCKER_CONTAINERS[current as DockerContainer];
|
|
128
|
+
|
|
129
|
+
if (config && config.dependsOn) {
|
|
130
|
+
for (const dep of config.dependsOn) {
|
|
131
|
+
if (!resolved.has(dep)) {
|
|
132
|
+
resolved.add(dep);
|
|
133
|
+
queue.push(dep);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return Array.from(resolved);
|
|
140
|
+
}
|
|
141
|
+
|
|
100
142
|
export async function configureDockerCompose(projectDir: string, selectedContainers: string[]) {
|
|
101
143
|
const s = spinner();
|
|
102
144
|
s.start('Configuring Docker Compose...');
|
|
@@ -109,10 +151,17 @@ export async function configureDockerCompose(projectDir: string, selectedContain
|
|
|
109
151
|
return;
|
|
110
152
|
}
|
|
111
153
|
|
|
154
|
+
const resolvedContainers = resolveContainerDependencies(selectedContainers);
|
|
155
|
+
const addedDependencies = resolvedContainers.filter(c => !selectedContainers.includes(c));
|
|
156
|
+
|
|
157
|
+
if (addedDependencies.length > 0) {
|
|
158
|
+
s.message(`Auto-including dependencies: ${color.cyan(addedDependencies.join(', '))}`);
|
|
159
|
+
}
|
|
160
|
+
|
|
112
161
|
let content = await fs.readFile(dockerComposePath, 'utf8');
|
|
113
162
|
|
|
114
163
|
const allContainers = Object.keys(DOCKER_CONTAINERS) as DockerContainer[];
|
|
115
|
-
const containersToRemove = allContainers.filter(c => !
|
|
164
|
+
const containersToRemove = allContainers.filter(c => !resolvedContainers.includes(c));
|
|
116
165
|
|
|
117
166
|
for (const container of containersToRemove) {
|
|
118
167
|
const containerRegex = new RegExp(
|
|
@@ -120,14 +169,28 @@ export async function configureDockerCompose(projectDir: string, selectedContain
|
|
|
120
169
|
'g'
|
|
121
170
|
);
|
|
122
171
|
content = content.replace(containerRegex, '');
|
|
172
|
+
|
|
173
|
+
// delete `./docker/<container>/`
|
|
174
|
+
const dockerDirPath = path.join(projectDir, 'docker', container);
|
|
175
|
+
if (await fs.pathExists(dockerDirPath)) {
|
|
176
|
+
await fs.remove(dockerDirPath);
|
|
177
|
+
s.message(`Removed ${color.cyan(dockerDirPath)}`);
|
|
178
|
+
}
|
|
123
179
|
}
|
|
124
180
|
|
|
125
181
|
content = content.replace(/ # -- \w+ --\n/g, '');
|
|
126
182
|
content = content.replace(/ # \/\/ \w+ \/\/\n/g, '');
|
|
127
183
|
|
|
128
184
|
await fs.writeFile(dockerComposePath, content);
|
|
185
|
+
|
|
186
|
+
// check if `./docker/` is empty
|
|
187
|
+
const dockerDir = path.join(projectDir, 'docker');
|
|
188
|
+
if (await fs.pathExists(dockerDir) && (await fs.readdir(dockerDir)).length === 0) {
|
|
189
|
+
await fs.remove(dockerDir);
|
|
190
|
+
s.message(`Removed ${color.cyan(dockerDir)} ${color.gray('(because it was empty)')}`);
|
|
191
|
+
}
|
|
129
192
|
|
|
130
|
-
s.stop(`Configured Docker Compose with ${color.cyan(
|
|
193
|
+
s.stop(`Configured Docker Compose with ${color.cyan(resolvedContainers.length)} container(s)`);
|
|
131
194
|
} catch (error) {
|
|
132
195
|
s.stop('Failed to configure Docker Compose');
|
|
133
196
|
throw error;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/helpers/transform.ts"],"sourcesContent":["import fg from 'fast-glob';\r\nimport fs from 'fs-extra';\r\nimport path from 'path';\r\nimport { spinner } from '@clack/prompts';\r\nimport color from 'picocolors';\r\n\r\nconst DOCKER_CONTAINERS = {\r\n postgres: {\r\n label: 'PostgreSQL 16 (Database)',\r\n services: ['postgres'],\r\n volumes: ['postgres_data'],\r\n },\r\n mailpit: {\r\n label: 'Mailpit (Email testing)',\r\n services: ['mailpit'],\r\n volumes: [],\r\n },\r\n minio: {\r\n label: 'MinIO (S3-compatible storage)',\r\n services: ['minio', 'minio-create-bucket'],\r\n volumes: ['minio_data'],\r\n },\r\n} as const;\r\n\r\nexport type DockerContainer = keyof typeof DOCKER_CONTAINERS;\r\n\r\nexport async function replaceScope(projectDir: string, newScope: string) {\r\n const s = spinner();\r\n s.start(`Replacing scope with ${color.cyan(newScope)}...`);\r\n\r\n try {\r\n const files = await fg('**/*', {\r\n cwd: projectDir,\r\n ignore: [\r\n '**/.git/**',\r\n '**/node_modules/**',\r\n '**/.turbo/**',\r\n '**/dist/**',\r\n '**/.next/**',\r\n '**/pnpm-lock.yaml',\r\n '**/yarn.lock',\r\n '**/package-lock.json',\r\n '**/bun.lockb',\r\n ],\r\n absolute: true,\r\n });\r\n\r\n await Promise.all(\r\n files.map(async (file) => {\r\n try {\r\n const content = await fs.readFile(file, 'utf8');\r\n if (content.includes('@acme')) {\r\n const newContent = content.replace(/@acme/g, newScope);\r\n await fs.writeFile(file, newContent);\r\n }\r\n } catch (e) {\r\n }\r\n })\r\n );\r\n \r\n s.stop(`Replaced scope with ${color.cyan(newScope)}`);\r\n } catch (error) {\r\n s.stop('Failed to replace scope');\r\n throw error;\r\n }\r\n}\r\n\r\nexport async function setupEnv(projectDir: string) {\r\n const envExample = path.join(projectDir, '.env.example');\r\n const envDest = path.join(projectDir, '.env');\r\n\r\n if (await fs.pathExists(envExample)) {\r\n await fs.copy(envExample, envDest);\r\n }\r\n}\r\n\r\nexport function getDockerContainers() {\r\n return Object.entries(DOCKER_CONTAINERS).map(([value, config]) => ({\r\n value,\r\n label: config.label,\r\n }));\r\n}\r\n\r\nexport async function deleteDockerCompose(projectDir: string) {\r\n const s = spinner();\r\n s.start('Removing Docker Compose setup...');\r\n\r\n try {\r\n const dockerComposePath = path.join(projectDir, 'docker-compose.yml');\r\n if (await fs.pathExists(dockerComposePath)) {\r\n await fs.remove(dockerComposePath);\r\n }\r\n s.stop('Removed Docker Compose setup');\r\n } catch (error) {\r\n s.stop('Failed to remove Docker Compose setup');\r\n throw error;\r\n }\r\n}\r\n\r\nexport async function configureDockerCompose(projectDir: string, selectedContainers: string[]) {\r\n const s = spinner();\r\n s.start('Configuring Docker Compose...');\r\n\r\n try {\r\n const dockerComposePath = path.join(projectDir, 'docker-compose.yml');\r\n \r\n if (!(await fs.pathExists(dockerComposePath))) {\r\n s.stop('Docker Compose file not found');\r\n return;\r\n }\r\n\r\n let content = await fs.readFile(dockerComposePath, 'utf8');\r\n\r\n const allContainers = Object.keys(DOCKER_CONTAINERS) as DockerContainer[];\r\n const containersToRemove = allContainers.filter(c => !selectedContainers.includes(c));\r\n\r\n for (const container of containersToRemove) {\r\n const containerRegex = new RegExp(\r\n ` # -- ${container} --\\\\n[\\\\s\\\\S]*? # // ${container} //\\\\n`,\r\n 'g'\r\n );\r\n content = content.replace(containerRegex, '');\r\n }\r\n\r\n content = content.replace(/ # -- \\w+ --\\n/g, '');\r\n content = content.replace(/ # \\/\\/ \\w+ \\/\\/\\n/g, '');\r\n\r\n await fs.writeFile(dockerComposePath, content);\r\n \r\n s.stop(`Configured Docker Compose with ${color.cyan(selectedContainers.length)} container(s)`);\r\n } catch (error) {\r\n s.stop('Failed to configure Docker Compose');\r\n throw error;\r\n }\r\n}\r\n\r\n"],"mappings":"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","names":[]}
|