@perma-tools/cli 0.0.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/README.md +159 -0
- package/dist/actions.d.ts +12 -0
- package/dist/actions.js +157 -0
- package/dist/cli-parser.d.ts +21 -0
- package/dist/cli-parser.js +141 -0
- package/dist/configs/axios.config.d.ts +2 -0
- package/dist/configs/axios.config.js +12 -0
- package/dist/configs/biome.config.d.ts +2 -0
- package/dist/configs/biome.config.js +12 -0
- package/dist/configs/cookies-next.config.d.ts +2 -0
- package/dist/configs/cookies-next.config.js +6 -0
- package/dist/configs/date-fns.config.d.ts +2 -0
- package/dist/configs/date-fns.config.js +6 -0
- package/dist/configs/eslint-prettier.config.d.ts +2 -0
- package/dist/configs/eslint-prettier.config.js +35 -0
- package/dist/configs/framer-motion.config.d.ts +2 -0
- package/dist/configs/framer-motion.config.js +6 -0
- package/dist/configs/ky.config.d.ts +2 -0
- package/dist/configs/ky.config.js +12 -0
- package/dist/configs/lucide-react.config.d.ts +2 -0
- package/dist/configs/lucide-react.config.js +6 -0
- package/dist/configs/nuqs.config.d.ts +2 -0
- package/dist/configs/nuqs.config.js +12 -0
- package/dist/configs/react-hook-form.config.d.ts +2 -0
- package/dist/configs/react-hook-form.config.js +6 -0
- package/dist/configs/recharts.config.d.ts +2 -0
- package/dist/configs/recharts.config.js +6 -0
- package/dist/configs/tanstack-query.config.d.ts +2 -0
- package/dist/configs/tanstack-query.config.js +19 -0
- package/dist/configs/zod.config.d.ts +2 -0
- package/dist/configs/zod.config.js +6 -0
- package/dist/dependency-versions.d.ts +13 -0
- package/dist/dependency-versions.js +50 -0
- package/dist/git-setup.d.ts +23 -0
- package/dist/git-setup.js +275 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +537 -0
- package/dist/project-generator.d.ts +15 -0
- package/dist/project-generator.js +311 -0
- package/dist/snippet-manager.d.ts +11 -0
- package/dist/snippet-manager.js +76 -0
- package/dist/snippets/axios/index.ts +6 -0
- package/dist/snippets/biome/biome.json +93 -0
- package/dist/snippets/eslint-prettier/eslintignore +6 -0
- package/dist/snippets/eslint-prettier/eslintrc.js +3 -0
- package/dist/snippets/eslint-prettier/prettierignore +9 -0
- package/dist/snippets/eslint-prettier/prettierrc.js +9 -0
- package/dist/snippets/ky/index.ts +5 -0
- package/dist/snippets/react-query/index.tsx +53 -0
- package/dist/snippets/vscode/extensions.json +3 -0
- package/dist/snippets/vscode/settings.json +19 -0
- package/dist/templates/frontend/next15/base/.env.example +3 -0
- package/dist/templates/frontend/next15/base/README.md +50 -0
- package/dist/templates/frontend/next15/base/next.config.ts +7 -0
- package/dist/templates/frontend/next15/base/package.json +23 -0
- package/dist/templates/frontend/next15/base/postcss.config.mjs +8 -0
- package/dist/templates/frontend/next15/base/public/public.md +12 -0
- package/dist/templates/frontend/next15/base/src/@types/@types.md +7 -0
- package/dist/templates/frontend/next15/base/src/@types/types.d.ts +1 -0
- package/dist/templates/frontend/next15/base/src/app/(application)/page.tsx +50 -0
- package/dist/templates/frontend/next15/base/src/app/favicon.ico +0 -0
- package/dist/templates/frontend/next15/base/src/app/layout.tsx +23 -0
- package/dist/templates/frontend/next15/base/src/app/providers.tsx +5 -0
- package/dist/templates/frontend/next15/base/src/components/components.md +9 -0
- package/dist/templates/frontend/next15/base/src/constants/constants.md +10 -0
- package/dist/templates/frontend/next15/base/src/hooks/hooks.md +11 -0
- package/dist/templates/frontend/next15/base/src/lib/lib.md +9 -0
- package/dist/templates/frontend/next15/base/src/services/services.md +14 -0
- package/dist/templates/frontend/next15/base/src/styles/globals.css +1 -0
- package/dist/templates/frontend/next15/base/src/types/types.md +15 -0
- package/dist/templates/frontend/next15/base/src/utils/utils.md +18 -0
- package/dist/templates/frontend/next15/base/tsconfig.json +26 -0
- package/dist/types.d.ts +60 -0
- package/dist/types.js +1 -0
- package/package.json +62 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { access, mkdir } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { intro, isCancel, multiselect, outro, select, text, } from "@clack/prompts";
|
|
5
|
+
import { optionsToConfig, parseArguments, validateOptions, } from "./cli-parser.js";
|
|
6
|
+
import { GitSetup } from "./git-setup.js";
|
|
7
|
+
import { ProjectGenerator } from "./project-generator.js";
|
|
8
|
+
async function runHybridMode(options) {
|
|
9
|
+
const config = { ...options };
|
|
10
|
+
// 0. Nome do projeto (obrigatΓ³rio)
|
|
11
|
+
if (!config.projectName) {
|
|
12
|
+
const projectName = await text({
|
|
13
|
+
message: "π Qual o nome do projeto?",
|
|
14
|
+
placeholder: "meu-projeto",
|
|
15
|
+
validate: (value) => {
|
|
16
|
+
if (!value)
|
|
17
|
+
return "O nome do projeto Γ© obrigatΓ³rio";
|
|
18
|
+
// Regras do npm para nomes de pacotes
|
|
19
|
+
if (!/^[a-z0-9-]+$/.test(value)) {
|
|
20
|
+
return "Use apenas letras minΓΊsculas, nΓΊmeros e hΓfens";
|
|
21
|
+
}
|
|
22
|
+
if (value.startsWith("-") || value.startsWith(".")) {
|
|
23
|
+
return "O nome nΓ£o pode comeΓ§ar com hΓfen ou ponto";
|
|
24
|
+
}
|
|
25
|
+
if (value.endsWith("-") || value.endsWith(".")) {
|
|
26
|
+
return "O nome nΓ£o pode terminar com hΓfen ou ponto";
|
|
27
|
+
}
|
|
28
|
+
if (value.length > 214) {
|
|
29
|
+
return "O nome deve ter no mΓ‘ximo 214 caracteres";
|
|
30
|
+
}
|
|
31
|
+
if (/^[0-9]/.test(value)) {
|
|
32
|
+
return "O nome nΓ£o pode comeΓ§ar com nΓΊmeros";
|
|
33
|
+
}
|
|
34
|
+
// Nomes reservados do npm
|
|
35
|
+
const reservedNames = ["node_modules", "favicon.ico"];
|
|
36
|
+
if (reservedNames.includes(value.toLowerCase())) {
|
|
37
|
+
return "Este nome Γ© reservado e nΓ£o pode ser usado";
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
if (isCancel(projectName)) {
|
|
42
|
+
outro("β OperaΓ§Γ£o cancelada");
|
|
43
|
+
process.exit(0);
|
|
44
|
+
}
|
|
45
|
+
config.projectName = projectName;
|
|
46
|
+
}
|
|
47
|
+
config.projectPath = join(process.cwd(), config.projectName);
|
|
48
|
+
// 1. Package Manager
|
|
49
|
+
if (!config.packageManager) {
|
|
50
|
+
config.packageManager = (await select({
|
|
51
|
+
message: "π¦ Qual package manager deseja usar?",
|
|
52
|
+
options: [
|
|
53
|
+
{ value: "pnpm", label: "pnpm" },
|
|
54
|
+
{ value: "yarn", label: "yarn" },
|
|
55
|
+
{ value: "npm", label: "npm" },
|
|
56
|
+
],
|
|
57
|
+
}));
|
|
58
|
+
}
|
|
59
|
+
// 2. Tipo da aplicaΓ§Γ£o
|
|
60
|
+
if (!config.applicationType) {
|
|
61
|
+
config.applicationType = (await select({
|
|
62
|
+
message: "ποΈ Qual tipo de aplicaΓ§Γ£o vocΓͺ quer?",
|
|
63
|
+
options: [
|
|
64
|
+
{ value: "frontend", label: "Frontend" },
|
|
65
|
+
{ value: "backend", label: "Backend" },
|
|
66
|
+
],
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
// Fluxo condicional baseado no tipo de aplicaΓ§Γ£o
|
|
70
|
+
if (config.applicationType === "frontend") {
|
|
71
|
+
// 3. Framework (apenas para frontend)
|
|
72
|
+
if (!config.framework) {
|
|
73
|
+
config.framework = (await select({
|
|
74
|
+
message: "β‘ Qual framework?",
|
|
75
|
+
options: [
|
|
76
|
+
{ value: "nextjs-15", label: "NextJS 15.x" },
|
|
77
|
+
{
|
|
78
|
+
value: "vitejs-6",
|
|
79
|
+
label: "ViteJS 6.x (em breve)",
|
|
80
|
+
hint: "Ainda nΓ£o disponΓvel",
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
}));
|
|
84
|
+
// Validar se ViteJS foi selecionado
|
|
85
|
+
if (config.framework === "vitejs-6") {
|
|
86
|
+
console.error("\nβ ViteJS ainda nΓ£o estΓ‘ disponΓvel nesta versΓ£o.");
|
|
87
|
+
console.error("π‘ Use NextJS 15.x ou aguarde a prΓ³xima versΓ£o.\n");
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// 4. Cliente HTTP
|
|
92
|
+
if (!config.httpClient) {
|
|
93
|
+
config.httpClient = (await select({
|
|
94
|
+
message: "π Qual cliente HTTP deseja usar?",
|
|
95
|
+
options: [
|
|
96
|
+
{ value: "ky", label: "ky" },
|
|
97
|
+
{ value: "axios", label: "axios" },
|
|
98
|
+
{ value: "fetch", label: "none (fetch)" },
|
|
99
|
+
],
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
// 5. Linter
|
|
103
|
+
if (!config.linter) {
|
|
104
|
+
config.linter = (await select({
|
|
105
|
+
message: "β¨ Qual linter deseja usar?",
|
|
106
|
+
options: [
|
|
107
|
+
{ value: "biome", label: "Biome" },
|
|
108
|
+
{ value: "eslint-prettier", label: "Eslint + Prettier" },
|
|
109
|
+
],
|
|
110
|
+
}));
|
|
111
|
+
}
|
|
112
|
+
// 6. Libs adicionais (sΓ³ pergunta se nΓ£o foi passado)
|
|
113
|
+
if (!config.additionalLibs || config.additionalLibs.length === 0) {
|
|
114
|
+
config.additionalLibs = (await multiselect({
|
|
115
|
+
message: "π Libs adicionais (pode selecionar mais de uma):",
|
|
116
|
+
options: [
|
|
117
|
+
{ value: "nuqs", label: "nuqs" },
|
|
118
|
+
{ value: "tanstack-query", label: "tanstack query" },
|
|
119
|
+
{ value: "date-fns", label: "date-fns" },
|
|
120
|
+
{ value: "zod", label: "zod" },
|
|
121
|
+
{
|
|
122
|
+
value: "react-hook-form",
|
|
123
|
+
label: "react hook form + @hookform/resolvers",
|
|
124
|
+
},
|
|
125
|
+
{ value: "cookies-next", label: "cookies-next" },
|
|
126
|
+
{ value: "framer-motion", label: "framer-motion" },
|
|
127
|
+
{ value: "lucide-react", label: "lucide-react" },
|
|
128
|
+
{ value: "recharts", label: "recharts" },
|
|
129
|
+
],
|
|
130
|
+
required: false,
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
133
|
+
// 7. shadcn/ui (sΓ³ pergunta se nΓ£o foi passado via flag)
|
|
134
|
+
if (config.withShadcn === undefined) {
|
|
135
|
+
const useShadcn = (await select({
|
|
136
|
+
message: "π¨ Deseja usar shadcn/ui?",
|
|
137
|
+
options: [
|
|
138
|
+
{ value: true, label: "Sim, configurar shadcn/ui" },
|
|
139
|
+
{ value: false, label: "NΓ£o" },
|
|
140
|
+
],
|
|
141
|
+
}));
|
|
142
|
+
config.withShadcn = useShadcn;
|
|
143
|
+
}
|
|
144
|
+
// 7.1. Cor do shadcn (sΓ³ pergunta se withShadcn = true e nΓ£o foi passado)
|
|
145
|
+
if (config.withShadcn && !config.shadcnColor) {
|
|
146
|
+
config.shadcnColor = (await select({
|
|
147
|
+
message: "π¨ Qual cor base deseja usar no shadcn/ui?",
|
|
148
|
+
options: [
|
|
149
|
+
{ value: "neutral", label: "Neutral (cinza neutro)" },
|
|
150
|
+
{ value: "slate", label: "Slate (cinza azulado)" },
|
|
151
|
+
{ value: "gray", label: "Gray (cinza mΓ©dio)" },
|
|
152
|
+
{ value: "zinc", label: "Zinc (cinza metΓ‘lico)" },
|
|
153
|
+
{ value: "stone", label: "Stone (cinza terroso)" },
|
|
154
|
+
],
|
|
155
|
+
}));
|
|
156
|
+
}
|
|
157
|
+
// 7.2. Componentes shadcn (sΓ³ pergunta se withShadcn = true e nΓ£o foram passados)
|
|
158
|
+
if (config.withShadcn &&
|
|
159
|
+
(!config.shadcnComponents || config.shadcnComponents.length === 0)) {
|
|
160
|
+
config.shadcnComponents = (await multiselect({
|
|
161
|
+
message: "π§© Quais componentes do shadcn/ui deseja adicionar?",
|
|
162
|
+
options: [
|
|
163
|
+
{ value: "button", label: "button" },
|
|
164
|
+
{ value: "input", label: "input" },
|
|
165
|
+
{ value: "card", label: "card" },
|
|
166
|
+
{ value: "dialog", label: "dialog" },
|
|
167
|
+
{ value: "dropdown-menu", label: "dropdown-menu" },
|
|
168
|
+
{ value: "label", label: "label" },
|
|
169
|
+
{ value: "select", label: "select" },
|
|
170
|
+
{ value: "textarea", label: "textarea" },
|
|
171
|
+
{ value: "toast", label: "toast" },
|
|
172
|
+
{ value: "form", label: "form" },
|
|
173
|
+
{ value: "table", label: "table" },
|
|
174
|
+
{ value: "tabs", label: "tabs" },
|
|
175
|
+
],
|
|
176
|
+
required: false,
|
|
177
|
+
}));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// 8. Instalar dependΓͺncias automaticamente (sΓ³ pergunta se nΓ£o foi passado)
|
|
181
|
+
if (config.shouldInstallDeps === undefined) {
|
|
182
|
+
const shouldInstall = (await select({
|
|
183
|
+
message: "π¦ Deseja instalar as dependΓͺncias automaticamente?",
|
|
184
|
+
options: [
|
|
185
|
+
{ value: true, label: "Sim, instalar agora" },
|
|
186
|
+
{ value: false, label: "NΓ£o, vou instalar depois" },
|
|
187
|
+
],
|
|
188
|
+
}));
|
|
189
|
+
config.shouldInstallDeps = shouldInstall;
|
|
190
|
+
}
|
|
191
|
+
// 9. Setup Git e Deploy (sΓ³ pergunta se nΓ£o foi passado)
|
|
192
|
+
if (config.gitSetup === undefined) {
|
|
193
|
+
// Verificar quais CLIs estΓ£o disponΓveis
|
|
194
|
+
const hasGitHubCLI = await GitSetup.isGitHubCLIAvailable();
|
|
195
|
+
const hasVercelCLI = await GitSetup.isVercelCLIAvailable();
|
|
196
|
+
// Se nΓ£o tem nenhuma CLI, pular essa etapa
|
|
197
|
+
if (!hasGitHubCLI) {
|
|
198
|
+
console.log("\nπ‘ GitHub CLI (gh) nΓ£o encontrado ou nΓ£o autenticado.");
|
|
199
|
+
console.log(" Para habilitar criaΓ§Γ£o automΓ‘tica de repos, instale: https://cli.github.com/\n");
|
|
200
|
+
config.gitSetup = "none";
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
// Mostrar aviso se nΓ£o tiver Vercel CLI (para projetos frontend)
|
|
204
|
+
if (!hasVercelCLI && config.applicationType === "frontend") {
|
|
205
|
+
console.log("\nπ‘ Vercel CLI nΓ£o encontrado. Deploy automΓ‘tico nΓ£o estarΓ‘ disponΓvel.");
|
|
206
|
+
console.log(" Para habilitar: npm i -g vercel && vercel login\n");
|
|
207
|
+
}
|
|
208
|
+
// Montar opΓ§Γ΅es baseado nas CLIs disponΓveis
|
|
209
|
+
const options = [];
|
|
210
|
+
// OpΓ§Γ£o de repo + deploy (sΓ³ se tiver ambas CLIs e for frontend)
|
|
211
|
+
if (hasGitHubCLI &&
|
|
212
|
+
hasVercelCLI &&
|
|
213
|
+
config.applicationType === "frontend") {
|
|
214
|
+
options.push({
|
|
215
|
+
value: "repo-and-deploy",
|
|
216
|
+
label: "Criar repositΓ³rio no GitHub e configurar deploy na Vercel",
|
|
217
|
+
hint: "Recomendado para projetos frontend",
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
// OpΓ§Γ£o de apenas repo (sempre disponΓvel se tiver gh CLI)
|
|
221
|
+
if (hasGitHubCLI) {
|
|
222
|
+
options.push({
|
|
223
|
+
value: "repo-only",
|
|
224
|
+
label: "Apenas criar repositΓ³rio no GitHub",
|
|
225
|
+
hint: "Sem configuraΓ§Γ£o de deploy",
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
// OpΓ§Γ£o de nΓ£o configurar (sempre disponΓvel)
|
|
229
|
+
options.push({
|
|
230
|
+
value: "none",
|
|
231
|
+
label: "NΓ£o configurar agora",
|
|
232
|
+
hint: "VocΓͺ pode configurar manualmente depois",
|
|
233
|
+
});
|
|
234
|
+
const setupOption = (await select({
|
|
235
|
+
message: "π Deseja configurar repositΓ³rio Git e deploy?",
|
|
236
|
+
options,
|
|
237
|
+
}));
|
|
238
|
+
config.gitSetup = setupOption;
|
|
239
|
+
}
|
|
240
|
+
// 9.1. Se escolheu criar repo, perguntar detalhes
|
|
241
|
+
if (config.gitSetup !== "none") {
|
|
242
|
+
// Nome do repositΓ³rio
|
|
243
|
+
if (!config.repoName) {
|
|
244
|
+
const repoName = (await text({
|
|
245
|
+
message: "π Qual o nome do repositΓ³rio?",
|
|
246
|
+
placeholder: config.projectName,
|
|
247
|
+
initialValue: config.projectName,
|
|
248
|
+
validate: (value) => {
|
|
249
|
+
if (!value)
|
|
250
|
+
return "O nome do repositΓ³rio Γ© obrigatΓ³rio";
|
|
251
|
+
if (!/^[a-zA-Z0-9._-]+$/.test(value)) {
|
|
252
|
+
return "Use apenas letras, nΓΊmeros, pontos, hΓfens e underscores";
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
}));
|
|
256
|
+
if (isCancel(repoName)) {
|
|
257
|
+
outro("β OperaΓ§Γ£o cancelada");
|
|
258
|
+
process.exit(0);
|
|
259
|
+
}
|
|
260
|
+
config.repoName = repoName;
|
|
261
|
+
}
|
|
262
|
+
// OrganizaΓ§Γ£o (se nΓ£o foi passado via flag)
|
|
263
|
+
if (!config.repoOrg) {
|
|
264
|
+
const repoLocation = (await select({
|
|
265
|
+
message: "π Onde deseja criar o repositΓ³rio?",
|
|
266
|
+
options: [
|
|
267
|
+
{
|
|
268
|
+
value: "personal",
|
|
269
|
+
label: "Meu perfil pessoal",
|
|
270
|
+
hint: "github.com/seu-usuario",
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
value: "organization",
|
|
274
|
+
label: "Em uma organizaΓ§Γ£o",
|
|
275
|
+
hint: "github.com/org-name",
|
|
276
|
+
},
|
|
277
|
+
],
|
|
278
|
+
}));
|
|
279
|
+
if (repoLocation === "organization") {
|
|
280
|
+
// Buscar organizaΓ§Γ΅es do usuΓ‘rio
|
|
281
|
+
console.log("\nπ Buscando suas organizaΓ§Γ΅es...");
|
|
282
|
+
const orgs = await GitSetup.getGitHubOrganizations();
|
|
283
|
+
if (orgs.length === 0) {
|
|
284
|
+
console.log("β οΈ Nenhuma organizaΓ§Γ£o encontrada ou GitHub CLI nΓ£o autenticado.");
|
|
285
|
+
console.log("π‘ Criando no perfil pessoal...\n");
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
const selectedOrg = (await select({
|
|
289
|
+
message: "π’ Selecione a organizaΓ§Γ£o:",
|
|
290
|
+
options: orgs.map((org) => ({
|
|
291
|
+
value: org,
|
|
292
|
+
label: org,
|
|
293
|
+
})),
|
|
294
|
+
}));
|
|
295
|
+
if (isCancel(selectedOrg)) {
|
|
296
|
+
outro("β OperaΓ§Γ£o cancelada");
|
|
297
|
+
process.exit(0);
|
|
298
|
+
}
|
|
299
|
+
config.repoOrg = selectedOrg;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
// Visibilidade do repositΓ³rio
|
|
304
|
+
if (!config.repoVisibility) {
|
|
305
|
+
config.repoVisibility = (await select({
|
|
306
|
+
message: "π Qual a visibilidade do repositΓ³rio?",
|
|
307
|
+
options: [
|
|
308
|
+
{
|
|
309
|
+
value: "public",
|
|
310
|
+
label: "PΓΊblico",
|
|
311
|
+
hint: "Qualquer pessoa pode ver",
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
value: "private",
|
|
315
|
+
label: "Privado",
|
|
316
|
+
hint: "Apenas vocΓͺ e colaboradores",
|
|
317
|
+
},
|
|
318
|
+
],
|
|
319
|
+
}));
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return config;
|
|
324
|
+
}
|
|
325
|
+
async function generateProject(config) {
|
|
326
|
+
const generator = new ProjectGenerator();
|
|
327
|
+
try {
|
|
328
|
+
// Verificar se o diretΓ³rio jΓ‘ existe
|
|
329
|
+
try {
|
|
330
|
+
await access(config.projectPath);
|
|
331
|
+
console.error("\nβ Erro: O diretΓ³rio jΓ‘ existe!");
|
|
332
|
+
console.error(` Caminho: ${config.projectPath}`);
|
|
333
|
+
console.error("\nπ‘ Escolha um nome diferente ou remova o diretΓ³rio existente.\n");
|
|
334
|
+
process.exit(1);
|
|
335
|
+
}
|
|
336
|
+
catch {
|
|
337
|
+
// DiretΓ³rio nΓ£o existe, podemos prosseguir
|
|
338
|
+
}
|
|
339
|
+
// Criar diretΓ³rio do projeto
|
|
340
|
+
await mkdir(config.projectPath, { recursive: true });
|
|
341
|
+
// Gerar projeto
|
|
342
|
+
await generator.generate(config);
|
|
343
|
+
// Setup Git e Deploy (se configurado)
|
|
344
|
+
if (config.gitSetup && config.gitSetup !== "none") {
|
|
345
|
+
const gitSetup = new GitSetup({
|
|
346
|
+
projectPath: config.projectPath,
|
|
347
|
+
projectName: config.projectName,
|
|
348
|
+
repoName: config.repoName,
|
|
349
|
+
repoOrg: config.repoOrg,
|
|
350
|
+
visibility: config.repoVisibility,
|
|
351
|
+
withVercel: config.gitSetup === "repo-and-deploy" &&
|
|
352
|
+
config.applicationType === "frontend",
|
|
353
|
+
});
|
|
354
|
+
try {
|
|
355
|
+
// Inicializar Git
|
|
356
|
+
await gitSetup.initialize();
|
|
357
|
+
// Criar repositΓ³rio no GitHub
|
|
358
|
+
const repoUrl = await gitSetup.createGitHubRepo();
|
|
359
|
+
console.log(`\nπ RepositΓ³rio: ${repoUrl}`);
|
|
360
|
+
// Configurar Vercel se necessΓ‘rio
|
|
361
|
+
if (config.gitSetup === "repo-and-deploy" &&
|
|
362
|
+
config.applicationType === "frontend") {
|
|
363
|
+
await gitSetup.setupVercelDeploy();
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
catch (error) {
|
|
367
|
+
console.error("\nβ οΈ Aviso: Erro ao configurar Git/Deploy:");
|
|
368
|
+
console.error(error.message);
|
|
369
|
+
console.error("\nπ‘ VocΓͺ pode configurar manualmente depois.");
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
// Sucesso!
|
|
373
|
+
console.log("\n");
|
|
374
|
+
outro("β¨ Projeto criado com sucesso!");
|
|
375
|
+
console.log("\nπ PrΓ³ximos passos:\n");
|
|
376
|
+
console.log(` cd ${config.projectName}`);
|
|
377
|
+
if (!config.shouldInstallDeps) {
|
|
378
|
+
console.log(` ${config.packageManager} install`);
|
|
379
|
+
}
|
|
380
|
+
if (!config.gitSetup || config.gitSetup === "none") {
|
|
381
|
+
console.log(` git init && git add . && git commit -m "initial commit"`);
|
|
382
|
+
}
|
|
383
|
+
console.log(` ${config.packageManager} ${config.packageManager === "npm" ? "run " : ""}dev`);
|
|
384
|
+
console.log("");
|
|
385
|
+
}
|
|
386
|
+
catch (error) {
|
|
387
|
+
console.error("\nβ Erro ao criar projeto:", error);
|
|
388
|
+
outro("Falha ao criar o projeto");
|
|
389
|
+
process.exit(1);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
async function main() {
|
|
393
|
+
// Verificar se hΓ‘ argumentos CLI (exceto --help e --version que o commander jΓ‘ trata)
|
|
394
|
+
const args = process.argv.slice(2);
|
|
395
|
+
const hasFlags = args.length > 0 &&
|
|
396
|
+
!args.every((arg) => arg === "--help" || arg === "-h" || arg === "--version" || arg === "-V");
|
|
397
|
+
if (hasFlags) {
|
|
398
|
+
// Modo CLI com flags ou hΓbrido
|
|
399
|
+
const options = parseArguments();
|
|
400
|
+
// Validar opΓ§Γ΅es antes de prosseguir
|
|
401
|
+
const errors = validateOptions(options);
|
|
402
|
+
if (errors.length > 0) {
|
|
403
|
+
console.error("\n");
|
|
404
|
+
console.error("βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ");
|
|
405
|
+
console.error("β β ERRO DE VALIDAΓΓO β");
|
|
406
|
+
console.error("βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ");
|
|
407
|
+
console.error("\n");
|
|
408
|
+
errors.forEach((error) => {
|
|
409
|
+
console.error(` ${error}`);
|
|
410
|
+
});
|
|
411
|
+
console.error("\n");
|
|
412
|
+
console.error("π‘ Dica: Use --help para ver as opΓ§Γ΅es disponΓveis");
|
|
413
|
+
console.error("\n");
|
|
414
|
+
process.exit(1);
|
|
415
|
+
}
|
|
416
|
+
// Validar disponibilidade de CLIs se Git setup foi especificado
|
|
417
|
+
if (options.gitSetup && options.gitSetup !== "none") {
|
|
418
|
+
const hasGitHubCLI = await GitSetup.isGitHubCLIAvailable();
|
|
419
|
+
const hasVercelCLI = await GitSetup.isVercelCLIAvailable();
|
|
420
|
+
if (!hasGitHubCLI) {
|
|
421
|
+
console.error("\nβ Erro: GitHub CLI (gh) nΓ£o encontrado ou nΓ£o autenticado.");
|
|
422
|
+
console.error(" Instale e autentique: https://cli.github.com/");
|
|
423
|
+
console.error(" Ou use a CLI sem --git-setup para pular essa configuraΓ§Γ£o.\n");
|
|
424
|
+
process.exit(1);
|
|
425
|
+
}
|
|
426
|
+
if (options.gitSetup === "repo-and-deploy" && !hasVercelCLI) {
|
|
427
|
+
console.error("\nβ οΈ Aviso: Vercel CLI nΓ£o encontrado ou nΓ£o autenticado.");
|
|
428
|
+
console.error(" Para deploy automΓ‘tico: npm i -g vercel && vercel login");
|
|
429
|
+
console.error(" Ajustando para criar apenas o repositΓ³rio...\n");
|
|
430
|
+
options.gitSetup = "repo-only";
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
console.clear();
|
|
434
|
+
intro("π Bem-vindo ao Gerador de Projetos!");
|
|
435
|
+
// Converter options para config parcial
|
|
436
|
+
const partialConfig = optionsToConfig(options);
|
|
437
|
+
// Executar modo hΓbrido (pergunta apenas o que falta)
|
|
438
|
+
const config = await runHybridMode(partialConfig);
|
|
439
|
+
// Exibir resumo final
|
|
440
|
+
console.log("\nπ RESUMO DAS SUAS ESCOLHAS:\n");
|
|
441
|
+
console.log("βββββββββββββββββββββββββββββββββββββββ");
|
|
442
|
+
console.log(`π Nome do Projeto: ${config.projectName}`);
|
|
443
|
+
console.log(`π¦ Package Manager: ${config.packageManager}`);
|
|
444
|
+
console.log(`ποΈ Tipo de AplicaΓ§Γ£o: ${config.applicationType}`);
|
|
445
|
+
if (config.applicationType === "frontend") {
|
|
446
|
+
console.log(`β‘ Framework: ${config.framework}`);
|
|
447
|
+
console.log(`π Cliente HTTP: ${config.httpClient}`);
|
|
448
|
+
console.log(`β¨ Linter: ${config.linter}`);
|
|
449
|
+
if (config.additionalLibs && config.additionalLibs.length > 0) {
|
|
450
|
+
console.log(`π Libs Adicionais: ${config.additionalLibs.join(", ")}`);
|
|
451
|
+
}
|
|
452
|
+
else {
|
|
453
|
+
console.log("π Libs Adicionais: Nenhuma selecionada");
|
|
454
|
+
}
|
|
455
|
+
if (config.withShadcn) {
|
|
456
|
+
if (config.shadcnComponents && config.shadcnComponents.length > 0) {
|
|
457
|
+
console.log(`π¨ shadcn/ui: Sim (${config.shadcnColor || "neutral"}, ${config.shadcnComponents.length} componente(s))`);
|
|
458
|
+
}
|
|
459
|
+
else {
|
|
460
|
+
console.log(`π¨ shadcn/ui: Sim (${config.shadcnColor || "neutral"}, apenas init)`);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
console.log("π¨ shadcn/ui: NΓ£o");
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
// Git Setup
|
|
468
|
+
if (config.gitSetup && config.gitSetup !== "none") {
|
|
469
|
+
const setupLabel = config.gitSetup === "repo-and-deploy"
|
|
470
|
+
? "Repo GitHub + Deploy Vercel"
|
|
471
|
+
: "Apenas Repo GitHub";
|
|
472
|
+
const repoFullName = config.repoOrg
|
|
473
|
+
? `${config.repoOrg}/${config.repoName}`
|
|
474
|
+
: config.repoName;
|
|
475
|
+
console.log(`π Git Setup: ${setupLabel}`);
|
|
476
|
+
console.log(`π¦ RepositΓ³rio: ${repoFullName} (${config.repoVisibility})`);
|
|
477
|
+
}
|
|
478
|
+
else {
|
|
479
|
+
console.log("π Git Setup: NΓ£o configurado");
|
|
480
|
+
}
|
|
481
|
+
console.log("βββββββββββββββββββββββββββββββββββββββ\n");
|
|
482
|
+
await generateProject(config);
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
// Modo interativo puro
|
|
486
|
+
console.clear();
|
|
487
|
+
intro("π Bem-vindo ao Gerador de Projetos!");
|
|
488
|
+
const config = await runHybridMode({});
|
|
489
|
+
// Exibir resumo final
|
|
490
|
+
console.log("\nπ RESUMO DAS SUAS ESCOLHAS:\n");
|
|
491
|
+
console.log("βββββββββββββββββββββββββββββββββββββββ");
|
|
492
|
+
console.log(`π Nome do Projeto: ${config.projectName}`);
|
|
493
|
+
console.log(`π¦ Package Manager: ${config.packageManager}`);
|
|
494
|
+
console.log(`ποΈ Tipo de AplicaΓ§Γ£o: ${config.applicationType}`);
|
|
495
|
+
if (config.applicationType === "frontend") {
|
|
496
|
+
console.log(`β‘ Framework: ${config.framework}`);
|
|
497
|
+
console.log(`π Cliente HTTP: ${config.httpClient}`);
|
|
498
|
+
console.log(`β¨ Linter: ${config.linter}`);
|
|
499
|
+
if (config.additionalLibs && config.additionalLibs.length > 0) {
|
|
500
|
+
console.log(`π Libs Adicionais: ${config.additionalLibs.join(", ")}`);
|
|
501
|
+
}
|
|
502
|
+
else {
|
|
503
|
+
console.log("π Libs Adicionais: Nenhuma selecionada");
|
|
504
|
+
}
|
|
505
|
+
if (config.withShadcn) {
|
|
506
|
+
if (config.shadcnComponents && config.shadcnComponents.length > 0) {
|
|
507
|
+
console.log(`π¨ shadcn/ui: Sim (${config.shadcnColor || "neutral"}, ${config.shadcnComponents.length} componente(s))`);
|
|
508
|
+
}
|
|
509
|
+
else {
|
|
510
|
+
console.log(`π¨ shadcn/ui: Sim (${config.shadcnColor || "neutral"}, apenas init)`);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
else {
|
|
514
|
+
console.log("π¨ shadcn/ui: NΓ£o");
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
// Git Setup
|
|
518
|
+
if (config.gitSetup && config.gitSetup !== "none") {
|
|
519
|
+
const setupLabel = config.gitSetup === "repo-and-deploy"
|
|
520
|
+
? "Repo GitHub + Deploy Vercel"
|
|
521
|
+
: "Apenas Repo GitHub";
|
|
522
|
+
const repoFullName = config.repoOrg
|
|
523
|
+
? `${config.repoOrg}/${config.repoName}`
|
|
524
|
+
: config.repoName;
|
|
525
|
+
console.log(`π Git Setup: ${setupLabel}`);
|
|
526
|
+
console.log(`π¦ RepositΓ³rio: ${repoFullName} (${config.repoVisibility})`);
|
|
527
|
+
}
|
|
528
|
+
else {
|
|
529
|
+
console.log("π Git Setup: NΓ£o configurado");
|
|
530
|
+
}
|
|
531
|
+
console.log("βββββββββββββββββββββββββββββββββββββββ\n");
|
|
532
|
+
// Gerar o projeto
|
|
533
|
+
console.log("");
|
|
534
|
+
await generateProject(config);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ProjectConfig } from "./types.js";
|
|
2
|
+
export declare class ProjectGenerator {
|
|
3
|
+
private snippetManager;
|
|
4
|
+
private rootPath;
|
|
5
|
+
constructor(rootPath?: string);
|
|
6
|
+
generate(config: ProjectConfig): Promise<void>;
|
|
7
|
+
private copyTemplate;
|
|
8
|
+
private getTemplatePath;
|
|
9
|
+
private processSnippets;
|
|
10
|
+
private updatePackageJson;
|
|
11
|
+
private createEnvFile;
|
|
12
|
+
private installDependencies;
|
|
13
|
+
private setupShadcn;
|
|
14
|
+
private createVscodeConfig;
|
|
15
|
+
}
|