create-turbo-kit 1.0.2 → 1.2.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/dist/{chunk-G5KXW3XA.js → chunk-5F6FI7NU.js} +22 -2
- package/dist/chunk-5F6FI7NU.js.map +1 -0
- package/dist/{chunk-MBDFMIAE.js → chunk-7W32JAIP.js} +2 -1
- package/dist/{chunk-MBDFMIAE.js.map → chunk-7W32JAIP.js.map} +1 -1
- package/dist/chunk-BMN5Q4NA.js +171 -0
- package/dist/chunk-BMN5Q4NA.js.map +1 -0
- package/dist/cli.js +59 -5
- package/dist/cli.js.map +1 -1
- package/dist/helpers/install.d.ts +2 -1
- package/dist/helpers/install.js +3 -1
- package/dist/helpers/scaffold.js +1 -1
- package/dist/helpers/transform.d.ts +34 -1
- package/dist/helpers/transform.js +7 -1
- package/package.json +1 -1
- package/src/cli.ts +63 -4
- package/src/helpers/install.ts +22 -0
- package/src/helpers/scaffold.ts +1 -0
- package/src/helpers/transform.ts +137 -0
- package/dist/chunk-G5KXW3XA.js.map +0 -1
- package/dist/chunk-GB72MU2M.js +0 -56
- package/dist/chunk-GB72MU2M.js.map +0 -1
|
@@ -21,8 +21,28 @@ async function installDependencies(projectDir, packageManager) {
|
|
|
21
21
|
throw error;
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
+
async function initializeGit(projectDir) {
|
|
25
|
+
const s = spinner();
|
|
26
|
+
s.start("Initializing git repository...");
|
|
27
|
+
try {
|
|
28
|
+
await execa("git", ["init"], {
|
|
29
|
+
cwd: projectDir
|
|
30
|
+
});
|
|
31
|
+
await execa("git", ["add", "."], {
|
|
32
|
+
cwd: projectDir
|
|
33
|
+
});
|
|
34
|
+
await execa("git", ["commit", "-m", "Initial commit"], {
|
|
35
|
+
cwd: projectDir
|
|
36
|
+
});
|
|
37
|
+
s.stop("Initialized git repository");
|
|
38
|
+
} catch (error) {
|
|
39
|
+
s.stop("Failed to initialize git repository");
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
24
43
|
|
|
25
44
|
export {
|
|
26
|
-
installDependencies
|
|
45
|
+
installDependencies,
|
|
46
|
+
initializeGit
|
|
27
47
|
};
|
|
28
|
-
//# sourceMappingURL=chunk-
|
|
48
|
+
//# sourceMappingURL=chunk-5F6FI7NU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/helpers/install.ts"],"sourcesContent":["import { execa } from 'execa';\r\nimport { spinner } from '@clack/prompts';\r\nimport { type PackageManager, getInstallCommand } from '../utils/package-manager.js';\r\nimport color from 'picocolors';\r\n\r\nexport async function installDependencies(projectDir: string, packageManager: PackageManager) {\r\n const s = spinner();\r\n s.start(`Installing dependencies with ${color.cyan(packageManager)}...`);\r\n\r\n const installCmd = getInstallCommand(packageManager);\r\n const [command = \"npm\", ...args] = installCmd.split(' ');\r\n\r\n try {\r\n await execa(command, args, {\r\n cwd: projectDir,\r\n });\r\n s.stop(`Installed dependencies`);\r\n } catch (error) {\r\n s.stop(`Failed to install dependencies`);\r\n throw error;\r\n }\r\n}\r\n\r\nexport async function initializeGit(projectDir: string) {\r\n const s = spinner();\r\n s.start('Initializing git repository...');\r\n\r\n try {\r\n await execa('git', ['init'], {\r\n cwd: projectDir,\r\n });\r\n await execa('git', ['add', '.'], {\r\n cwd: projectDir,\r\n });\r\n await execa('git', ['commit', '-m', 'Initial commit'], {\r\n cwd: projectDir,\r\n });\r\n\r\n s.stop('Initialized git repository');\r\n } catch (error) {\r\n s.stop('Failed to initialize git repository');\r\n throw error;\r\n }\r\n}\r\n\r\n"],"mappings":";;;;;AAAA,SAAS,aAAa;AACtB,SAAS,eAAe;AAExB,OAAO,WAAW;AAElB,eAAsB,oBAAoB,YAAoB,gBAAgC;AAC5F,QAAM,IAAI,QAAQ;AAClB,IAAE,MAAM,gCAAgC,MAAM,KAAK,cAAc,CAAC,KAAK;AAEvE,QAAM,aAAa,kBAAkB,cAAc;AACnD,QAAM,CAAC,UAAU,OAAO,GAAG,IAAI,IAAI,WAAW,MAAM,GAAG;AAEvD,MAAI;AACF,UAAM,MAAM,SAAS,MAAM;AAAA,MACzB,KAAK;AAAA,IACP,CAAC;AACD,MAAE,KAAK,wBAAwB;AAAA,EACjC,SAAS,OAAO;AACd,MAAE,KAAK,gCAAgC;AACvC,UAAM;AAAA,EACR;AACF;AAEA,eAAsB,cAAc,YAAoB;AACtD,QAAM,IAAI,QAAQ;AAClB,IAAE,MAAM,gCAAgC;AAExC,MAAI;AACF,UAAM,MAAM,OAAO,CAAC,MAAM,GAAG;AAAA,MAC3B,KAAK;AAAA,IACP,CAAC;AACD,UAAM,MAAM,OAAO,CAAC,OAAO,GAAG,GAAG;AAAA,MAC/B,KAAK;AAAA,IACP,CAAC;AACD,UAAM,MAAM,OAAO,CAAC,UAAU,MAAM,gBAAgB,GAAG;AAAA,MACrD,KAAK;AAAA,IACP,CAAC;AAED,MAAE,KAAK,4BAA4B;AAAA,EACrC,SAAS,OAAO;AACd,MAAE,KAAK,qCAAqC;AAC5C,UAAM;AAAA,EACR;AACF;","names":[]}
|
|
@@ -20,6 +20,7 @@ async function scaffoldProject({ projectName, packageManager }) {
|
|
|
20
20
|
"--package-manager",
|
|
21
21
|
packageManager,
|
|
22
22
|
"--skip-install",
|
|
23
|
+
"--no-git",
|
|
23
24
|
projectName
|
|
24
25
|
]);
|
|
25
26
|
s.stop(`Scaffolded project in ${color.cyan(projectName)}`);
|
|
@@ -32,4 +33,4 @@ async function scaffoldProject({ projectName, packageManager }) {
|
|
|
32
33
|
export {
|
|
33
34
|
scaffoldProject
|
|
34
35
|
};
|
|
35
|
-
//# sourceMappingURL=chunk-
|
|
36
|
+
//# sourceMappingURL=chunk-7W32JAIP.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/helpers/scaffold.ts"],"sourcesContent":["import { execa } from 'execa';\r\nimport { spinner } from '@clack/prompts';\r\nimport { type PackageManager, getRunner } from '../utils/package-manager.js';\r\nimport color from 'picocolors';\r\n\r\nexport interface ScaffoldOptions {\r\n projectName: string;\r\n packageManager: PackageManager;\r\n}\r\n\r\nexport async function scaffoldProject({ projectName, packageManager }: ScaffoldOptions) {\r\n const s = spinner();\r\n s.start(`Scaffolding project in ${color.cyan(projectName)}...`);\r\n\r\n const runner = getRunner(packageManager);\r\n const [command = 'npx', ...args] = runner.split(' ');\r\n \r\n try {\r\n await execa(command, [\r\n ...args,\r\n 'create-turbo@latest',\r\n '-e',\r\n 'https://github.com/Badbird5907/turbo-kit',\r\n '--package-manager',\r\n packageManager,\r\n '--skip-install',\r\n projectName\r\n ]);\r\n \r\n s.stop(`Scaffolded project in ${color.cyan(projectName)}`);\r\n } catch (error) {\r\n s.stop(`Failed to scaffold project`);\r\n throw error;\r\n }\r\n}\r\n\r\n"],"mappings":";;;;;AAAA,SAAS,aAAa;AACtB,SAAS,eAAe;AAExB,OAAO,WAAW;AAOlB,eAAsB,gBAAgB,EAAE,aAAa,eAAe,GAAoB;AACtF,QAAM,IAAI,QAAQ;AAClB,IAAE,MAAM,0BAA0B,MAAM,KAAK,WAAW,CAAC,KAAK;AAE9D,QAAM,SAAS,UAAU,cAAc;AACvC,QAAM,CAAC,UAAU,OAAO,GAAG,IAAI,IAAI,OAAO,MAAM,GAAG;AAEnD,MAAI;AACF,UAAM,MAAM,SAAS;AAAA,MACnB,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,MAAE,KAAK,yBAAyB,MAAM,KAAK,WAAW,CAAC,EAAE;AAAA,EAC3D,SAAS,OAAO;AACd,MAAE,KAAK,4BAA4B;AACnC,UAAM;AAAA,EACR;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/helpers/scaffold.ts"],"sourcesContent":["import { execa } from 'execa';\r\nimport { spinner } from '@clack/prompts';\r\nimport { type PackageManager, getRunner } from '../utils/package-manager.js';\r\nimport color from 'picocolors';\r\n\r\nexport interface ScaffoldOptions {\r\n projectName: string;\r\n packageManager: PackageManager;\r\n}\r\n\r\nexport async function scaffoldProject({ projectName, packageManager }: ScaffoldOptions) {\r\n const s = spinner();\r\n s.start(`Scaffolding project in ${color.cyan(projectName)}...`);\r\n\r\n const runner = getRunner(packageManager);\r\n const [command = 'npx', ...args] = runner.split(' ');\r\n \r\n try {\r\n await execa(command, [\r\n ...args,\r\n 'create-turbo@latest',\r\n '-e',\r\n 'https://github.com/Badbird5907/turbo-kit',\r\n '--package-manager',\r\n packageManager,\r\n '--skip-install',\r\n '--no-git',\r\n projectName\r\n ]);\r\n \r\n s.stop(`Scaffolded project in ${color.cyan(projectName)}`);\r\n } catch (error) {\r\n s.stop(`Failed to scaffold project`);\r\n throw error;\r\n }\r\n}\r\n\r\n"],"mappings":";;;;;AAAA,SAAS,aAAa;AACtB,SAAS,eAAe;AAExB,OAAO,WAAW;AAOlB,eAAsB,gBAAgB,EAAE,aAAa,eAAe,GAAoB;AACtF,QAAM,IAAI,QAAQ;AAClB,IAAE,MAAM,0BAA0B,MAAM,KAAK,WAAW,CAAC,KAAK;AAE9D,QAAM,SAAS,UAAU,cAAc;AACvC,QAAM,CAAC,UAAU,OAAO,GAAG,IAAI,IAAI,OAAO,MAAM,GAAG;AAEnD,MAAI;AACF,UAAM,MAAM,SAAS;AAAA,MACnB,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,MAAE,KAAK,yBAAyB,MAAM,KAAK,WAAW,CAAC,EAAE;AAAA,EAC3D,SAAS,OAAO;AACd,MAAE,KAAK,4BAA4B;AACnC,UAAM;AAAA,EACR;AACF;","names":[]}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
// src/helpers/transform.ts
|
|
2
|
+
import fg from "fast-glob";
|
|
3
|
+
import fs from "fs-extra";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { spinner } from "@clack/prompts";
|
|
6
|
+
import color from "picocolors";
|
|
7
|
+
var DOCKER_CONTAINERS = {
|
|
8
|
+
postgres: {
|
|
9
|
+
label: "PostgreSQL 16 (Database)",
|
|
10
|
+
services: ["postgres"],
|
|
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
|
+
mailpit: {
|
|
21
|
+
label: "Mailpit (Email testing)",
|
|
22
|
+
services: ["mailpit"],
|
|
23
|
+
volumes: [],
|
|
24
|
+
dependsOn: []
|
|
25
|
+
},
|
|
26
|
+
minio: {
|
|
27
|
+
label: "MinIO (S3-compatible storage)",
|
|
28
|
+
services: ["minio", "minio-create-bucket"],
|
|
29
|
+
volumes: ["minio_data"],
|
|
30
|
+
dependsOn: []
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
async function replaceScope(projectDir, newScope) {
|
|
34
|
+
const s = spinner();
|
|
35
|
+
s.start(`Replacing scope with ${color.cyan(newScope)}...`);
|
|
36
|
+
try {
|
|
37
|
+
const files = await fg("**/*", {
|
|
38
|
+
cwd: projectDir,
|
|
39
|
+
ignore: [
|
|
40
|
+
"**/.git/**",
|
|
41
|
+
"**/node_modules/**",
|
|
42
|
+
"**/.turbo/**",
|
|
43
|
+
"**/dist/**",
|
|
44
|
+
"**/.next/**",
|
|
45
|
+
"**/pnpm-lock.yaml",
|
|
46
|
+
"**/yarn.lock",
|
|
47
|
+
"**/package-lock.json",
|
|
48
|
+
"**/bun.lockb"
|
|
49
|
+
],
|
|
50
|
+
absolute: true
|
|
51
|
+
});
|
|
52
|
+
await Promise.all(
|
|
53
|
+
files.map(async (file) => {
|
|
54
|
+
try {
|
|
55
|
+
const content = await fs.readFile(file, "utf8");
|
|
56
|
+
if (content.includes("@acme")) {
|
|
57
|
+
const newContent = content.replace(/@acme/g, newScope);
|
|
58
|
+
await fs.writeFile(file, newContent);
|
|
59
|
+
}
|
|
60
|
+
} catch (e) {
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
);
|
|
64
|
+
s.stop(`Replaced scope with ${color.cyan(newScope)}`);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
s.stop("Failed to replace scope");
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async function setupEnv(projectDir) {
|
|
71
|
+
const envExample = path.join(projectDir, ".env.example");
|
|
72
|
+
const envDest = path.join(projectDir, ".env");
|
|
73
|
+
if (await fs.pathExists(envExample)) {
|
|
74
|
+
await fs.copy(envExample, envDest);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function getDockerContainers() {
|
|
78
|
+
return Object.entries(DOCKER_CONTAINERS).map(([value, config]) => ({
|
|
79
|
+
value,
|
|
80
|
+
label: config.label
|
|
81
|
+
}));
|
|
82
|
+
}
|
|
83
|
+
async function deleteDockerCompose(projectDir) {
|
|
84
|
+
const s = spinner();
|
|
85
|
+
s.start("Removing Docker Compose setup...");
|
|
86
|
+
try {
|
|
87
|
+
const dockerComposePath = path.join(projectDir, "docker-compose.yml");
|
|
88
|
+
if (await fs.pathExists(dockerComposePath)) {
|
|
89
|
+
await fs.remove(dockerComposePath);
|
|
90
|
+
s.message(`Removed ${color.cyan(dockerComposePath)}`);
|
|
91
|
+
}
|
|
92
|
+
const dockerDir = path.join(projectDir, "docker");
|
|
93
|
+
if (await fs.pathExists(dockerDir)) {
|
|
94
|
+
await fs.remove(dockerDir);
|
|
95
|
+
s.message(`Removed ${color.cyan(dockerDir)}`);
|
|
96
|
+
}
|
|
97
|
+
s.stop("Removed Docker Compose setup");
|
|
98
|
+
} catch (error) {
|
|
99
|
+
s.stop("Failed to remove Docker Compose setup");
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function resolveContainerDependencies(selectedContainers) {
|
|
104
|
+
const resolved = new Set(selectedContainers);
|
|
105
|
+
const queue = [...selectedContainers];
|
|
106
|
+
while (queue.length > 0) {
|
|
107
|
+
const current = queue.shift();
|
|
108
|
+
const config = DOCKER_CONTAINERS[current];
|
|
109
|
+
if (config && config.dependsOn) {
|
|
110
|
+
for (const dep of config.dependsOn) {
|
|
111
|
+
if (!resolved.has(dep)) {
|
|
112
|
+
resolved.add(dep);
|
|
113
|
+
queue.push(dep);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return Array.from(resolved);
|
|
119
|
+
}
|
|
120
|
+
async function configureDockerCompose(projectDir, selectedContainers) {
|
|
121
|
+
const s = spinner();
|
|
122
|
+
s.start("Configuring Docker Compose...");
|
|
123
|
+
try {
|
|
124
|
+
const dockerComposePath = path.join(projectDir, "docker-compose.yml");
|
|
125
|
+
if (!await fs.pathExists(dockerComposePath)) {
|
|
126
|
+
s.stop("Docker Compose file not found");
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const resolvedContainers = resolveContainerDependencies(selectedContainers);
|
|
130
|
+
const addedDependencies = resolvedContainers.filter((c) => !selectedContainers.includes(c));
|
|
131
|
+
if (addedDependencies.length > 0) {
|
|
132
|
+
s.message(`Auto-including dependencies: ${color.cyan(addedDependencies.join(", "))}`);
|
|
133
|
+
}
|
|
134
|
+
let content = await fs.readFile(dockerComposePath, "utf8");
|
|
135
|
+
const allContainers = Object.keys(DOCKER_CONTAINERS);
|
|
136
|
+
const containersToRemove = allContainers.filter((c) => !resolvedContainers.includes(c));
|
|
137
|
+
for (const container of containersToRemove) {
|
|
138
|
+
const containerRegex = new RegExp(
|
|
139
|
+
` # -- ${container} --\\n[\\s\\S]*? # // ${container} //\\n`,
|
|
140
|
+
"g"
|
|
141
|
+
);
|
|
142
|
+
content = content.replace(containerRegex, "");
|
|
143
|
+
const dockerDirPath = path.join(projectDir, "docker", container);
|
|
144
|
+
if (await fs.pathExists(dockerDirPath)) {
|
|
145
|
+
await fs.remove(dockerDirPath);
|
|
146
|
+
s.message(`Removed ${color.cyan(dockerDirPath)}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
content = content.replace(/ # -- \w+ --\n/g, "");
|
|
150
|
+
content = content.replace(/ # \/\/ \w+ \/\/\n/g, "");
|
|
151
|
+
await fs.writeFile(dockerComposePath, content);
|
|
152
|
+
const dockerDir = path.join(projectDir, "docker");
|
|
153
|
+
if (await fs.pathExists(dockerDir) && (await fs.readdir(dockerDir)).length === 0) {
|
|
154
|
+
await fs.remove(dockerDir);
|
|
155
|
+
s.message(`Removed ${color.cyan(dockerDir)} ${color.gray("(because it was empty)")}`);
|
|
156
|
+
}
|
|
157
|
+
s.stop(`Configured Docker Compose with ${color.cyan(resolvedContainers.length)} container(s)`);
|
|
158
|
+
} catch (error) {
|
|
159
|
+
s.stop("Failed to configure Docker Compose");
|
|
160
|
+
throw error;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export {
|
|
165
|
+
replaceScope,
|
|
166
|
+
setupEnv,
|
|
167
|
+
getDockerContainers,
|
|
168
|
+
deleteDockerCompose,
|
|
169
|
+
configureDockerCompose
|
|
170
|
+
};
|
|
171
|
+
//# sourceMappingURL=chunk-BMN5Q4NA.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 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
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
|
+
initializeGit,
|
|
2
3
|
installDependencies
|
|
3
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-5F6FI7NU.js";
|
|
4
5
|
import {
|
|
5
6
|
scaffoldProject
|
|
6
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-7W32JAIP.js";
|
|
7
8
|
import {
|
|
9
|
+
configureDockerCompose,
|
|
10
|
+
deleteDockerCompose,
|
|
11
|
+
getDockerContainers,
|
|
8
12
|
replaceScope,
|
|
9
13
|
setupEnv
|
|
10
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-BMN5Q4NA.js";
|
|
11
15
|
import "./chunk-EYEU3RGM.js";
|
|
12
16
|
|
|
13
17
|
// src/cli.ts
|
|
14
|
-
import { intro, outro, text, select, isCancel, cancel, confirm } from "@clack/prompts";
|
|
18
|
+
import { intro, outro, text, select, isCancel, cancel, confirm, multiselect } from "@clack/prompts";
|
|
15
19
|
import { Command } from "commander";
|
|
16
20
|
import color from "picocolors";
|
|
17
21
|
import fs from "fs-extra";
|
|
@@ -30,6 +34,11 @@ async function main() {
|
|
|
30
34
|
validate: (value) => {
|
|
31
35
|
if (!value) return "Please enter a name.";
|
|
32
36
|
if (/[^a-zA-Z0-9-_]/.test(value)) return "Project name can only contain letters, numbers, dashes and underscores.";
|
|
37
|
+
const projectDir2 = path.resolve(process.cwd(), value);
|
|
38
|
+
if (fs.pathExistsSync(projectDir2)) {
|
|
39
|
+
return "Project name already taken.";
|
|
40
|
+
}
|
|
41
|
+
return void 0;
|
|
33
42
|
}
|
|
34
43
|
});
|
|
35
44
|
if (isCancel(pName)) {
|
|
@@ -95,12 +104,57 @@ Your import statements will look like this: ${importStatement}`,
|
|
|
95
104
|
projectName,
|
|
96
105
|
packageManager
|
|
97
106
|
});
|
|
107
|
+
const wantsDocker = await confirm({
|
|
108
|
+
message: "Do you want to set up a local Docker Compose dev environment?",
|
|
109
|
+
initialValue: true
|
|
110
|
+
});
|
|
111
|
+
if (isCancel(wantsDocker)) {
|
|
112
|
+
cancel("Operation cancelled.");
|
|
113
|
+
process.exit(0);
|
|
114
|
+
}
|
|
115
|
+
if (wantsDocker) {
|
|
116
|
+
const dockerContainers = getDockerContainers();
|
|
117
|
+
const containers = await multiselect({
|
|
118
|
+
message: "Which containers do you want to include?",
|
|
119
|
+
options: dockerContainers,
|
|
120
|
+
initialValues: dockerContainers.map((container) => container.value),
|
|
121
|
+
required: false
|
|
122
|
+
});
|
|
123
|
+
if (isCancel(containers)) {
|
|
124
|
+
cancel("Operation cancelled.");
|
|
125
|
+
process.exit(0);
|
|
126
|
+
}
|
|
127
|
+
if (Array.isArray(containers) && containers.length > 0) {
|
|
128
|
+
await configureDockerCompose(projectDir, containers);
|
|
129
|
+
} else {
|
|
130
|
+
await deleteDockerCompose(projectDir);
|
|
131
|
+
}
|
|
132
|
+
} else {
|
|
133
|
+
await deleteDockerCompose(projectDir);
|
|
134
|
+
}
|
|
135
|
+
const shouldInstall = await confirm({
|
|
136
|
+
message: "Do you want to install dependencies now?",
|
|
137
|
+
initialValue: true
|
|
138
|
+
});
|
|
139
|
+
if (isCancel(shouldInstall)) {
|
|
140
|
+
cancel("Operation cancelled.");
|
|
141
|
+
process.exit(0);
|
|
142
|
+
}
|
|
98
143
|
await replaceScope(projectDir, scope);
|
|
99
144
|
await setupEnv(projectDir);
|
|
100
|
-
|
|
145
|
+
if (shouldInstall) {
|
|
146
|
+
await installDependencies(projectDir, packageManager);
|
|
147
|
+
}
|
|
148
|
+
await initializeGit(projectDir);
|
|
101
149
|
outro(color.green("Project initialized successfully!"));
|
|
102
150
|
console.log(`To get started:`);
|
|
103
151
|
console.log(color.cyan(` cd ${projectName}`));
|
|
152
|
+
if (!shouldInstall) {
|
|
153
|
+
console.log(color.cyan(` ${packageManager} install`));
|
|
154
|
+
}
|
|
155
|
+
if (wantsDocker) {
|
|
156
|
+
console.log(color.cyan(` docker compose up -d`));
|
|
157
|
+
}
|
|
104
158
|
console.log(color.cyan(` ${packageManager} run dev`));
|
|
105
159
|
console.log();
|
|
106
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 } 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 } from './helpers/transform.js';\r\nimport { installDependencies } 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 },\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 await replaceScope(projectDir, scope as string);\r\n await setupEnv(projectDir);\r\n await installDependencies(projectDir, packageManager as PackageManager);\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 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":"
|
|
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"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { PackageManager } from '../utils/package-manager.js';
|
|
2
2
|
|
|
3
3
|
declare function installDependencies(projectDir: string, packageManager: PackageManager): Promise<void>;
|
|
4
|
+
declare function initializeGit(projectDir: string): Promise<void>;
|
|
4
5
|
|
|
5
|
-
export { installDependencies };
|
|
6
|
+
export { initializeGit, installDependencies };
|
package/dist/helpers/install.js
CHANGED
package/dist/helpers/scaffold.js
CHANGED
|
@@ -1,4 +1,37 @@
|
|
|
1
|
+
declare const DOCKER_CONTAINERS: {
|
|
2
|
+
readonly postgres: {
|
|
3
|
+
readonly label: "PostgreSQL 16 (Database)";
|
|
4
|
+
readonly services: readonly ["postgres"];
|
|
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 mailpit: {
|
|
15
|
+
readonly label: "Mailpit (Email testing)";
|
|
16
|
+
readonly services: readonly ["mailpit"];
|
|
17
|
+
readonly volumes: readonly [];
|
|
18
|
+
readonly dependsOn: readonly [];
|
|
19
|
+
};
|
|
20
|
+
readonly minio: {
|
|
21
|
+
readonly label: "MinIO (S3-compatible storage)";
|
|
22
|
+
readonly services: readonly ["minio", "minio-create-bucket"];
|
|
23
|
+
readonly volumes: readonly ["minio_data"];
|
|
24
|
+
readonly dependsOn: readonly [];
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
type DockerContainer = keyof typeof DOCKER_CONTAINERS;
|
|
1
28
|
declare function replaceScope(projectDir: string, newScope: string): Promise<void>;
|
|
2
29
|
declare function setupEnv(projectDir: string): Promise<void>;
|
|
30
|
+
declare function getDockerContainers(): {
|
|
31
|
+
value: string;
|
|
32
|
+
label: "PostgreSQL 16 (Database)" | "pgAdmin 4.9 (Database management) [Depends on PostgreSQL]" | "Mailpit (Email testing)" | "MinIO (S3-compatible storage)";
|
|
33
|
+
}[];
|
|
34
|
+
declare function deleteDockerCompose(projectDir: string): Promise<void>;
|
|
35
|
+
declare function configureDockerCompose(projectDir: string, selectedContainers: string[]): Promise<void>;
|
|
3
36
|
|
|
4
|
-
export { replaceScope, setupEnv };
|
|
37
|
+
export { type DockerContainer, configureDockerCompose, deleteDockerCompose, getDockerContainers, replaceScope, setupEnv };
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
|
+
configureDockerCompose,
|
|
3
|
+
deleteDockerCompose,
|
|
4
|
+
getDockerContainers,
|
|
2
5
|
replaceScope,
|
|
3
6
|
setupEnv
|
|
4
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-BMN5Q4NA.js";
|
|
5
8
|
export {
|
|
9
|
+
configureDockerCompose,
|
|
10
|
+
deleteDockerCompose,
|
|
11
|
+
getDockerContainers,
|
|
6
12
|
replaceScope,
|
|
7
13
|
setupEnv
|
|
8
14
|
};
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { intro, outro, text, select, isCancel, cancel, confirm } from '@clack/prompts';
|
|
1
|
+
import { intro, outro, text, select, isCancel, cancel, confirm, multiselect } from '@clack/prompts';
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import color from 'picocolors';
|
|
4
4
|
import fs from 'fs-extra';
|
|
5
5
|
import path from 'path';
|
|
6
|
-
import { replaceScope, setupEnv } from './helpers/transform.js';
|
|
7
|
-
import { installDependencies } from './helpers/install.js';
|
|
6
|
+
import { replaceScope, setupEnv, getDockerContainers, configureDockerCompose, deleteDockerCompose } from './helpers/transform.js';
|
|
7
|
+
import { installDependencies, initializeGit } from './helpers/install.js';
|
|
8
8
|
import { type PackageManager } from './utils/package-manager.js';
|
|
9
9
|
import { scaffoldProject } from './helpers/scaffold.js';
|
|
10
10
|
|
|
@@ -30,6 +30,11 @@ async function main() {
|
|
|
30
30
|
validate: (value) => {
|
|
31
31
|
if (!value) return 'Please enter a name.';
|
|
32
32
|
if (/[^a-zA-Z0-9-_]/.test(value)) return 'Project name can only contain letters, numbers, dashes and underscores.';
|
|
33
|
+
const projectDir = path.resolve(process.cwd(), value);
|
|
34
|
+
if (fs.pathExistsSync(projectDir)) {
|
|
35
|
+
return 'Project name already taken.';
|
|
36
|
+
}
|
|
37
|
+
return undefined;
|
|
33
38
|
},
|
|
34
39
|
});
|
|
35
40
|
|
|
@@ -108,14 +113,68 @@ async function main() {
|
|
|
108
113
|
packageManager: packageManager as PackageManager,
|
|
109
114
|
});
|
|
110
115
|
|
|
116
|
+
const wantsDocker = await confirm({
|
|
117
|
+
message: 'Do you want to set up a local Docker Compose dev environment?',
|
|
118
|
+
initialValue: true,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
if (isCancel(wantsDocker)) {
|
|
122
|
+
cancel('Operation cancelled.');
|
|
123
|
+
process.exit(0);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (wantsDocker) {
|
|
127
|
+
const dockerContainers = getDockerContainers();
|
|
128
|
+
const containers = await multiselect({
|
|
129
|
+
message: 'Which containers do you want to include?',
|
|
130
|
+
options: dockerContainers,
|
|
131
|
+
initialValues: dockerContainers.map((container) => container.value),
|
|
132
|
+
required: false,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
if (isCancel(containers)) {
|
|
136
|
+
cancel('Operation cancelled.');
|
|
137
|
+
process.exit(0);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (Array.isArray(containers) && containers.length > 0) {
|
|
141
|
+
await configureDockerCompose(projectDir, containers as string[]);
|
|
142
|
+
} else {
|
|
143
|
+
await deleteDockerCompose(projectDir);
|
|
144
|
+
}
|
|
145
|
+
} else {
|
|
146
|
+
await deleteDockerCompose(projectDir);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const shouldInstall = await confirm({
|
|
150
|
+
message: 'Do you want to install dependencies now?',
|
|
151
|
+
initialValue: true,
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
if (isCancel(shouldInstall)) {
|
|
155
|
+
cancel('Operation cancelled.');
|
|
156
|
+
process.exit(0);
|
|
157
|
+
}
|
|
158
|
+
|
|
111
159
|
await replaceScope(projectDir, scope as string);
|
|
112
160
|
await setupEnv(projectDir);
|
|
113
|
-
|
|
161
|
+
|
|
162
|
+
if (shouldInstall) {
|
|
163
|
+
await installDependencies(projectDir, packageManager as PackageManager);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
await initializeGit(projectDir);
|
|
114
167
|
|
|
115
168
|
outro(color.green('Project initialized successfully!'));
|
|
116
169
|
|
|
117
170
|
console.log(`To get started:`);
|
|
118
171
|
console.log(color.cyan(` cd ${projectName}`));
|
|
172
|
+
if (!shouldInstall) {
|
|
173
|
+
console.log(color.cyan(` ${packageManager} install`));
|
|
174
|
+
}
|
|
175
|
+
if (wantsDocker) {
|
|
176
|
+
console.log(color.cyan(` docker compose up -d`));
|
|
177
|
+
}
|
|
119
178
|
console.log(color.cyan(` ${packageManager} run dev`));
|
|
120
179
|
|
|
121
180
|
console.log();
|
package/src/helpers/install.ts
CHANGED
|
@@ -21,3 +21,25 @@ export async function installDependencies(projectDir: string, packageManager: Pa
|
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
export async function initializeGit(projectDir: string) {
|
|
25
|
+
const s = spinner();
|
|
26
|
+
s.start('Initializing git repository...');
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
await execa('git', ['init'], {
|
|
30
|
+
cwd: projectDir,
|
|
31
|
+
});
|
|
32
|
+
await execa('git', ['add', '.'], {
|
|
33
|
+
cwd: projectDir,
|
|
34
|
+
});
|
|
35
|
+
await execa('git', ['commit', '-m', 'Initial commit'], {
|
|
36
|
+
cwd: projectDir,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
s.stop('Initialized git repository');
|
|
40
|
+
} catch (error) {
|
|
41
|
+
s.stop('Failed to initialize git repository');
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
package/src/helpers/scaffold.ts
CHANGED
package/src/helpers/transform.ts
CHANGED
|
@@ -4,6 +4,35 @@ import path from 'path';
|
|
|
4
4
|
import { spinner } from '@clack/prompts';
|
|
5
5
|
import color from 'picocolors';
|
|
6
6
|
|
|
7
|
+
const DOCKER_CONTAINERS = {
|
|
8
|
+
postgres: {
|
|
9
|
+
label: 'PostgreSQL 16 (Database)',
|
|
10
|
+
services: ['postgres'],
|
|
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
|
+
mailpit: {
|
|
21
|
+
label: 'Mailpit (Email testing)',
|
|
22
|
+
services: ['mailpit'],
|
|
23
|
+
volumes: [],
|
|
24
|
+
dependsOn: [],
|
|
25
|
+
},
|
|
26
|
+
minio: {
|
|
27
|
+
label: 'MinIO (S3-compatible storage)',
|
|
28
|
+
services: ['minio', 'minio-create-bucket'],
|
|
29
|
+
volumes: ['minio_data'],
|
|
30
|
+
dependsOn: [],
|
|
31
|
+
},
|
|
32
|
+
} as const;
|
|
33
|
+
|
|
34
|
+
export type DockerContainer = keyof typeof DOCKER_CONTAINERS;
|
|
35
|
+
|
|
7
36
|
export async function replaceScope(projectDir: string, newScope: string) {
|
|
8
37
|
const s = spinner();
|
|
9
38
|
s.start(`Replacing scope with ${color.cyan(newScope)}...`);
|
|
@@ -54,3 +83,111 @@ export async function setupEnv(projectDir: string) {
|
|
|
54
83
|
}
|
|
55
84
|
}
|
|
56
85
|
|
|
86
|
+
export function getDockerContainers() {
|
|
87
|
+
return Object.entries(DOCKER_CONTAINERS).map(([value, config]) => ({
|
|
88
|
+
value,
|
|
89
|
+
label: config.label,
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export async function deleteDockerCompose(projectDir: string) {
|
|
94
|
+
const s = spinner();
|
|
95
|
+
s.start('Removing Docker Compose setup...');
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
const dockerComposePath = path.join(projectDir, 'docker-compose.yml');
|
|
99
|
+
if (await fs.pathExists(dockerComposePath)) {
|
|
100
|
+
await fs.remove(dockerComposePath);
|
|
101
|
+
s.message(`Removed ${color.cyan(dockerComposePath)}`);
|
|
102
|
+
}
|
|
103
|
+
const dockerDir = path.join(projectDir, 'docker');
|
|
104
|
+
if (await fs.pathExists(dockerDir)) {
|
|
105
|
+
await fs.remove(dockerDir);
|
|
106
|
+
s.message(`Removed ${color.cyan(dockerDir)}`);
|
|
107
|
+
}
|
|
108
|
+
s.stop('Removed Docker Compose setup');
|
|
109
|
+
} catch (error) {
|
|
110
|
+
s.stop('Failed to remove Docker Compose setup');
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function resolveContainerDependencies(selectedContainers: string[]): string[] {
|
|
116
|
+
const resolved = new Set<string>(selectedContainers);
|
|
117
|
+
const queue = [...selectedContainers];
|
|
118
|
+
|
|
119
|
+
while (queue.length > 0) {
|
|
120
|
+
const current = queue.shift()!;
|
|
121
|
+
const config = DOCKER_CONTAINERS[current as DockerContainer];
|
|
122
|
+
|
|
123
|
+
if (config && config.dependsOn) {
|
|
124
|
+
for (const dep of config.dependsOn) {
|
|
125
|
+
if (!resolved.has(dep)) {
|
|
126
|
+
resolved.add(dep);
|
|
127
|
+
queue.push(dep);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return Array.from(resolved);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export async function configureDockerCompose(projectDir: string, selectedContainers: string[]) {
|
|
137
|
+
const s = spinner();
|
|
138
|
+
s.start('Configuring Docker Compose...');
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
const dockerComposePath = path.join(projectDir, 'docker-compose.yml');
|
|
142
|
+
|
|
143
|
+
if (!(await fs.pathExists(dockerComposePath))) {
|
|
144
|
+
s.stop('Docker Compose file not found');
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const resolvedContainers = resolveContainerDependencies(selectedContainers);
|
|
149
|
+
const addedDependencies = resolvedContainers.filter(c => !selectedContainers.includes(c));
|
|
150
|
+
|
|
151
|
+
if (addedDependencies.length > 0) {
|
|
152
|
+
s.message(`Auto-including dependencies: ${color.cyan(addedDependencies.join(', '))}`);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
let content = await fs.readFile(dockerComposePath, 'utf8');
|
|
156
|
+
|
|
157
|
+
const allContainers = Object.keys(DOCKER_CONTAINERS) as DockerContainer[];
|
|
158
|
+
const containersToRemove = allContainers.filter(c => !resolvedContainers.includes(c));
|
|
159
|
+
|
|
160
|
+
for (const container of containersToRemove) {
|
|
161
|
+
const containerRegex = new RegExp(
|
|
162
|
+
` # -- ${container} --\\n[\\s\\S]*? # // ${container} //\\n`,
|
|
163
|
+
'g'
|
|
164
|
+
);
|
|
165
|
+
content = content.replace(containerRegex, '');
|
|
166
|
+
|
|
167
|
+
// delete `./docker/<container>/`
|
|
168
|
+
const dockerDirPath = path.join(projectDir, 'docker', container);
|
|
169
|
+
if (await fs.pathExists(dockerDirPath)) {
|
|
170
|
+
await fs.remove(dockerDirPath);
|
|
171
|
+
s.message(`Removed ${color.cyan(dockerDirPath)}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
content = content.replace(/ # -- \w+ --\n/g, '');
|
|
176
|
+
content = content.replace(/ # \/\/ \w+ \/\/\n/g, '');
|
|
177
|
+
|
|
178
|
+
await fs.writeFile(dockerComposePath, content);
|
|
179
|
+
|
|
180
|
+
// check if `./docker/` is empty
|
|
181
|
+
const dockerDir = path.join(projectDir, 'docker');
|
|
182
|
+
if (await fs.pathExists(dockerDir) && (await fs.readdir(dockerDir)).length === 0) {
|
|
183
|
+
await fs.remove(dockerDir);
|
|
184
|
+
s.message(`Removed ${color.cyan(dockerDir)} ${color.gray('(because it was empty)')}`);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
s.stop(`Configured Docker Compose with ${color.cyan(resolvedContainers.length)} container(s)`);
|
|
188
|
+
} catch (error) {
|
|
189
|
+
s.stop('Failed to configure Docker Compose');
|
|
190
|
+
throw error;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/helpers/install.ts"],"sourcesContent":["import { execa } from 'execa';\r\nimport { spinner } from '@clack/prompts';\r\nimport { type PackageManager, getInstallCommand } from '../utils/package-manager.js';\r\nimport color from 'picocolors';\r\n\r\nexport async function installDependencies(projectDir: string, packageManager: PackageManager) {\r\n const s = spinner();\r\n s.start(`Installing dependencies with ${color.cyan(packageManager)}...`);\r\n\r\n const installCmd = getInstallCommand(packageManager);\r\n const [command = \"npm\", ...args] = installCmd.split(' ');\r\n\r\n try {\r\n await execa(command, args, {\r\n cwd: projectDir,\r\n });\r\n s.stop(`Installed dependencies`);\r\n } catch (error) {\r\n s.stop(`Failed to install dependencies`);\r\n throw error;\r\n }\r\n}\r\n\r\n"],"mappings":";;;;;AAAA,SAAS,aAAa;AACtB,SAAS,eAAe;AAExB,OAAO,WAAW;AAElB,eAAsB,oBAAoB,YAAoB,gBAAgC;AAC5F,QAAM,IAAI,QAAQ;AAClB,IAAE,MAAM,gCAAgC,MAAM,KAAK,cAAc,CAAC,KAAK;AAEvE,QAAM,aAAa,kBAAkB,cAAc;AACnD,QAAM,CAAC,UAAU,OAAO,GAAG,IAAI,IAAI,WAAW,MAAM,GAAG;AAEvD,MAAI;AACF,UAAM,MAAM,SAAS,MAAM;AAAA,MACzB,KAAK;AAAA,IACP,CAAC;AACD,MAAE,KAAK,wBAAwB;AAAA,EACjC,SAAS,OAAO;AACd,MAAE,KAAK,gCAAgC;AACvC,UAAM;AAAA,EACR;AACF;","names":[]}
|
package/dist/chunk-GB72MU2M.js
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
// src/helpers/transform.ts
|
|
2
|
-
import fg from "fast-glob";
|
|
3
|
-
import fs from "fs-extra";
|
|
4
|
-
import path from "path";
|
|
5
|
-
import { spinner } from "@clack/prompts";
|
|
6
|
-
import color from "picocolors";
|
|
7
|
-
async function replaceScope(projectDir, newScope) {
|
|
8
|
-
const s = spinner();
|
|
9
|
-
s.start(`Replacing scope with ${color.cyan(newScope)}...`);
|
|
10
|
-
try {
|
|
11
|
-
const files = await fg("**/*", {
|
|
12
|
-
cwd: projectDir,
|
|
13
|
-
ignore: [
|
|
14
|
-
"**/.git/**",
|
|
15
|
-
"**/node_modules/**",
|
|
16
|
-
"**/.turbo/**",
|
|
17
|
-
"**/dist/**",
|
|
18
|
-
"**/.next/**",
|
|
19
|
-
"**/pnpm-lock.yaml",
|
|
20
|
-
"**/yarn.lock",
|
|
21
|
-
"**/package-lock.json",
|
|
22
|
-
"**/bun.lockb"
|
|
23
|
-
],
|
|
24
|
-
absolute: true
|
|
25
|
-
});
|
|
26
|
-
await Promise.all(
|
|
27
|
-
files.map(async (file) => {
|
|
28
|
-
try {
|
|
29
|
-
const content = await fs.readFile(file, "utf8");
|
|
30
|
-
if (content.includes("@acme")) {
|
|
31
|
-
const newContent = content.replace(/@acme/g, newScope);
|
|
32
|
-
await fs.writeFile(file, newContent);
|
|
33
|
-
}
|
|
34
|
-
} catch (e) {
|
|
35
|
-
}
|
|
36
|
-
})
|
|
37
|
-
);
|
|
38
|
-
s.stop(`Replaced scope with ${color.cyan(newScope)}`);
|
|
39
|
-
} catch (error) {
|
|
40
|
-
s.stop("Failed to replace scope");
|
|
41
|
-
throw error;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
async function setupEnv(projectDir) {
|
|
45
|
-
const envExample = path.join(projectDir, ".env.example");
|
|
46
|
-
const envDest = path.join(projectDir, ".env");
|
|
47
|
-
if (await fs.pathExists(envExample)) {
|
|
48
|
-
await fs.copy(envExample, envDest);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export {
|
|
53
|
-
replaceScope,
|
|
54
|
-
setupEnv
|
|
55
|
-
};
|
|
56
|
-
//# sourceMappingURL=chunk-GB72MU2M.js.map
|
|
@@ -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\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\n"],"mappings":";AAAA,OAAO,QAAQ;AACf,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,eAAe;AACxB,OAAO,WAAW;AAElB,eAAsB,aAAa,YAAoB,UAAkB;AACvE,QAAM,IAAI,QAAQ;AAClB,IAAE,MAAM,wBAAwB,MAAM,KAAK,QAAQ,CAAC,KAAK;AAEzD,MAAI;AACF,UAAM,QAAQ,MAAM,GAAG,QAAQ;AAAA,MAC7B,KAAK;AAAA,MACL,QAAQ;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,UAAU;AAAA,IACZ,CAAC;AAED,UAAM,QAAQ;AAAA,MACZ,MAAM,IAAI,OAAO,SAAS;AACxB,YAAI;AACF,gBAAM,UAAU,MAAM,GAAG,SAAS,MAAM,MAAM;AAC9C,cAAI,QAAQ,SAAS,OAAO,GAAG;AAC7B,kBAAM,aAAa,QAAQ,QAAQ,UAAU,QAAQ;AACrD,kBAAM,GAAG,UAAU,MAAM,UAAU;AAAA,UACrC;AAAA,QACF,SAAS,GAAG;AAAA,QACZ;AAAA,MACF,CAAC;AAAA,IACH;AAEA,MAAE,KAAK,uBAAuB,MAAM,KAAK,QAAQ,CAAC,EAAE;AAAA,EACtD,SAAS,OAAO;AACd,MAAE,KAAK,yBAAyB;AAChC,UAAM;AAAA,EACR;AACF;AAEA,eAAsB,SAAS,YAAoB;AACjD,QAAM,aAAa,KAAK,KAAK,YAAY,cAAc;AACvD,QAAM,UAAU,KAAK,KAAK,YAAY,MAAM;AAE5C,MAAI,MAAM,GAAG,WAAW,UAAU,GAAG;AACnC,UAAM,GAAG,KAAK,YAAY,OAAO;AAAA,EACnC;AACF;","names":[]}
|