@nimbuslab/cli 0.7.0 → 0.9.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/MIGRATION-ROADMAP.md +201 -0
- package/dist/index.js +801 -69
- package/docs/CI-CD.md +11 -2
- package/package.json +1 -1
- package/src/commands/analyze.ts +210 -0
- package/src/commands/create.ts +432 -59
- package/src/commands/upgrade.ts +251 -0
- package/src/index.ts +19 -3
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import * as p from "@clack/prompts"
|
|
2
|
+
import pc from "picocolors"
|
|
3
|
+
import { analyze } from "./analyze"
|
|
4
|
+
|
|
5
|
+
interface UpgradePlan {
|
|
6
|
+
current: string
|
|
7
|
+
target: string
|
|
8
|
+
breakingChanges: string[]
|
|
9
|
+
steps: string[]
|
|
10
|
+
complexity: "low" | "medium" | "high"
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const UPGRADE_PLANS: Record<string, (currentVersion: string) => UpgradePlan | null> = {
|
|
14
|
+
next: (current) => {
|
|
15
|
+
const major = parseInt(current.replace(/[^0-9]/g, "").slice(0, 2))
|
|
16
|
+
if (major >= 16) return null
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
current: current,
|
|
20
|
+
target: "16.x",
|
|
21
|
+
complexity: major < 15 ? "high" : "medium",
|
|
22
|
+
breakingChanges: [
|
|
23
|
+
"next/image: Mudancas na API de otimizacao",
|
|
24
|
+
"Middleware: Novo formato de config",
|
|
25
|
+
"next.config: Algumas opcoes depreciadas",
|
|
26
|
+
"Turbopack: Agora e o bundler padrao",
|
|
27
|
+
],
|
|
28
|
+
steps: [
|
|
29
|
+
"Atualizar next para ^16.0.0",
|
|
30
|
+
"Atualizar react para ^19.0.0",
|
|
31
|
+
"Atualizar react-dom para ^19.0.0",
|
|
32
|
+
"Revisar next.config.ts",
|
|
33
|
+
"Testar build: bun run build",
|
|
34
|
+
"Testar dev: bun dev",
|
|
35
|
+
],
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
react: (current) => {
|
|
40
|
+
if (current.startsWith("19") || current.startsWith("^19")) return null
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
current: current,
|
|
44
|
+
target: "19.x",
|
|
45
|
+
complexity: "medium",
|
|
46
|
+
breakingChanges: [
|
|
47
|
+
"forwardRef: Nao mais necessario, ref e prop regular",
|
|
48
|
+
"useContext: Pode ser substituido por use(Context)",
|
|
49
|
+
"Suspense: Mudancas em fallback behavior",
|
|
50
|
+
"Async components: Novo suporte nativo",
|
|
51
|
+
],
|
|
52
|
+
steps: [
|
|
53
|
+
"Atualizar react para ^19.0.0",
|
|
54
|
+
"Atualizar react-dom para ^19.0.0",
|
|
55
|
+
"Atualizar @types/react para ^19.0.0",
|
|
56
|
+
"Remover forwardRef (usar ref como prop)",
|
|
57
|
+
"Revisar Suspense boundaries",
|
|
58
|
+
"Testar todos os componentes",
|
|
59
|
+
],
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
tailwind: (current) => {
|
|
64
|
+
if (current.startsWith("4") || current.startsWith("^4")) return null
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
current: current,
|
|
68
|
+
target: "4.x",
|
|
69
|
+
complexity: "medium",
|
|
70
|
+
breakingChanges: [
|
|
71
|
+
"Config: Agora e CSS-first (nao mais tailwind.config.js)",
|
|
72
|
+
"@apply: Sintaxe mudou",
|
|
73
|
+
"Cores: Novo sistema de tokens",
|
|
74
|
+
"Plugins: API diferente",
|
|
75
|
+
],
|
|
76
|
+
steps: [
|
|
77
|
+
"Atualizar tailwindcss para ^4.0.0",
|
|
78
|
+
"Converter tailwind.config.js para CSS",
|
|
79
|
+
"Atualizar globals.css com @import 'tailwindcss'",
|
|
80
|
+
"Revisar @apply usages",
|
|
81
|
+
"Atualizar plugins para v4",
|
|
82
|
+
"Testar todas as paginas",
|
|
83
|
+
],
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
bun: () => ({
|
|
88
|
+
current: "pnpm/npm/yarn",
|
|
89
|
+
target: "bun",
|
|
90
|
+
complexity: "low",
|
|
91
|
+
breakingChanges: [
|
|
92
|
+
"Lockfile: Formato diferente (bun.lockb)",
|
|
93
|
+
"Scripts: Alguns podem precisar ajuste",
|
|
94
|
+
"Workspaces: Sintaxe levemente diferente",
|
|
95
|
+
],
|
|
96
|
+
steps: [
|
|
97
|
+
"Remover node_modules",
|
|
98
|
+
"Remover pnpm-lock.yaml / package-lock.json / yarn.lock",
|
|
99
|
+
"Executar: bun install",
|
|
100
|
+
"Atualizar scripts no package.json (npx -> bunx)",
|
|
101
|
+
"Atualizar CI/CD configs",
|
|
102
|
+
"Testar: bun dev, bun build",
|
|
103
|
+
],
|
|
104
|
+
}),
|
|
105
|
+
|
|
106
|
+
drizzle: () => ({
|
|
107
|
+
current: "prisma",
|
|
108
|
+
target: "drizzle",
|
|
109
|
+
complexity: "high",
|
|
110
|
+
breakingChanges: [
|
|
111
|
+
"Schema: Formato TypeScript (nao mais .prisma)",
|
|
112
|
+
"Queries: API completamente diferente",
|
|
113
|
+
"Migrations: Sistema diferente",
|
|
114
|
+
"Relations: Declaracao diferente",
|
|
115
|
+
],
|
|
116
|
+
steps: [
|
|
117
|
+
"Instalar drizzle-orm e drizzle-kit",
|
|
118
|
+
"Converter schema.prisma para drizzle/schema.ts",
|
|
119
|
+
"Configurar drizzle.config.ts",
|
|
120
|
+
"Gerar migrations: bunx drizzle-kit generate",
|
|
121
|
+
"Atualizar todas as queries",
|
|
122
|
+
"Atualizar auth config (se usar)",
|
|
123
|
+
"Remover @prisma/client e prisma",
|
|
124
|
+
"Testar todas as operacoes de banco",
|
|
125
|
+
],
|
|
126
|
+
}),
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export async function upgrade(args: string[]) {
|
|
130
|
+
const showPlan = args.includes("--plan")
|
|
131
|
+
const target = args.find(a => !a.startsWith("-"))
|
|
132
|
+
|
|
133
|
+
console.log()
|
|
134
|
+
|
|
135
|
+
if (showPlan || !target) {
|
|
136
|
+
// Analyze first
|
|
137
|
+
console.log(pc.cyan(" Analisando projeto para plano de upgrade..."))
|
|
138
|
+
console.log()
|
|
139
|
+
|
|
140
|
+
const analysis = await analyze([".", "--quiet"])
|
|
141
|
+
|
|
142
|
+
console.log(pc.bold(" Upgrades Disponiveis:"))
|
|
143
|
+
console.log()
|
|
144
|
+
|
|
145
|
+
let hasUpgrades = false
|
|
146
|
+
|
|
147
|
+
// Check Next.js
|
|
148
|
+
if (analysis.frameworkVersion && analysis.framework === "nextjs") {
|
|
149
|
+
const planFn = UPGRADE_PLANS["next"]
|
|
150
|
+
if (planFn) {
|
|
151
|
+
const plan = planFn(analysis.frameworkVersion)
|
|
152
|
+
if (plan) {
|
|
153
|
+
hasUpgrades = true
|
|
154
|
+
printUpgradePlan("Next.js", plan)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Check React
|
|
160
|
+
if (analysis.dependencies["react"]) {
|
|
161
|
+
const planFn = UPGRADE_PLANS["react"]
|
|
162
|
+
if (planFn) {
|
|
163
|
+
const plan = planFn(analysis.dependencies["react"])
|
|
164
|
+
if (plan) {
|
|
165
|
+
hasUpgrades = true
|
|
166
|
+
printUpgradePlan("React", plan)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Check Tailwind
|
|
172
|
+
const tailwindDep = analysis.dependencies["tailwindcss"] || analysis.devDependencies["tailwindcss"]
|
|
173
|
+
if (tailwindDep) {
|
|
174
|
+
const planFn = UPGRADE_PLANS["tailwind"]
|
|
175
|
+
if (planFn) {
|
|
176
|
+
const plan = planFn(tailwindDep)
|
|
177
|
+
if (plan) {
|
|
178
|
+
hasUpgrades = true
|
|
179
|
+
printUpgradePlan("Tailwind CSS", plan)
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Check package manager
|
|
185
|
+
if (analysis.packageManager !== "bun") {
|
|
186
|
+
const planFn = UPGRADE_PLANS["bun"]
|
|
187
|
+
if (planFn) {
|
|
188
|
+
const plan = planFn("")
|
|
189
|
+
if (plan) {
|
|
190
|
+
hasUpgrades = true
|
|
191
|
+
printUpgradePlan("Package Manager", plan)
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Check Prisma -> Drizzle
|
|
197
|
+
if (analysis.database === "prisma") {
|
|
198
|
+
const planFn = UPGRADE_PLANS["drizzle"]
|
|
199
|
+
if (planFn) {
|
|
200
|
+
const plan = planFn("")
|
|
201
|
+
if (plan) {
|
|
202
|
+
hasUpgrades = true
|
|
203
|
+
printUpgradePlan("Database", plan)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (!hasUpgrades) {
|
|
209
|
+
console.log(pc.green(" Projeto ja esta atualizado!"))
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
console.log()
|
|
213
|
+
console.log(pc.dim(" Para executar um upgrade especifico:"))
|
|
214
|
+
console.log(pc.dim(" nimbus upgrade next"))
|
|
215
|
+
console.log(pc.dim(" nimbus upgrade tailwind"))
|
|
216
|
+
console.log(pc.dim(" nimbus upgrade bun"))
|
|
217
|
+
console.log()
|
|
218
|
+
|
|
219
|
+
return
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Execute specific upgrade
|
|
223
|
+
console.log(pc.yellow(` Upgrade ${target} ainda nao implementado.`))
|
|
224
|
+
console.log(pc.dim(" Por enquanto, siga os passos do --plan manualmente."))
|
|
225
|
+
console.log()
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function printUpgradePlan(name: string, plan: UpgradePlan) {
|
|
229
|
+
const complexityColor = {
|
|
230
|
+
low: pc.green,
|
|
231
|
+
medium: pc.yellow,
|
|
232
|
+
high: pc.red,
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
console.log(` ${pc.bold(name)}`)
|
|
236
|
+
console.log(` ${pc.dim("Atual:")} ${plan.current} ${pc.dim("->")} ${pc.cyan(plan.target)}`)
|
|
237
|
+
console.log(` ${pc.dim("Complexidade:")} ${complexityColor[plan.complexity](plan.complexity)}`)
|
|
238
|
+
console.log()
|
|
239
|
+
|
|
240
|
+
console.log(` ${pc.dim("Breaking Changes:")}`)
|
|
241
|
+
plan.breakingChanges.forEach(bc => {
|
|
242
|
+
console.log(` ${pc.yellow("!")} ${bc}`)
|
|
243
|
+
})
|
|
244
|
+
console.log()
|
|
245
|
+
|
|
246
|
+
console.log(` ${pc.dim("Passos:")}`)
|
|
247
|
+
plan.steps.forEach((step, i) => {
|
|
248
|
+
console.log(` ${pc.dim(`${i + 1}.`)} ${step}`)
|
|
249
|
+
})
|
|
250
|
+
console.log()
|
|
251
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
import * as p from "@clack/prompts"
|
|
4
4
|
import pc from "picocolors"
|
|
5
5
|
import { create } from "./commands/create"
|
|
6
|
+
import { analyze } from "./commands/analyze"
|
|
7
|
+
import { upgrade } from "./commands/upgrade"
|
|
6
8
|
|
|
7
9
|
const PACKAGE_NAME = "@nimbuslab/cli"
|
|
8
|
-
const CURRENT_VERSION = "0.
|
|
10
|
+
const CURRENT_VERSION = "0.9.0"
|
|
9
11
|
|
|
10
12
|
const LOGO = `
|
|
11
13
|
███╗ ██╗██╗███╗ ███╗██████╗ ██╗ ██╗███████╗
|
|
@@ -74,6 +76,10 @@ async function main() {
|
|
|
74
76
|
|
|
75
77
|
if (!command || command === "create") {
|
|
76
78
|
await create(args.slice(1))
|
|
79
|
+
} else if (command === "analyze") {
|
|
80
|
+
await analyze(args.slice(1))
|
|
81
|
+
} else if (command === "upgrade") {
|
|
82
|
+
await upgrade(args.slice(1))
|
|
77
83
|
} else if (command === "help" || command === "--help" || command === "-h") {
|
|
78
84
|
showHelp()
|
|
79
85
|
} else if (command === "version" || command === "--version" || command === "-v") {
|
|
@@ -91,14 +97,23 @@ ${pc.bold("Usage:")} nimbus [command] [options]
|
|
|
91
97
|
|
|
92
98
|
${pc.bold("Commands:")}
|
|
93
99
|
create [name] Create a new project
|
|
100
|
+
analyze [dir] Analyze project stack
|
|
101
|
+
upgrade [target] Upgrade dependencies
|
|
94
102
|
help Show this help
|
|
95
103
|
version Show version
|
|
96
104
|
|
|
97
105
|
${pc.bold("Templates:")}
|
|
98
106
|
--landing Landing page (Next.js 16 + Tailwind 4 + shadcn)
|
|
99
|
-
--app Web app (Landing + Better Auth +
|
|
107
|
+
--app Web app (Landing + Better Auth + Drizzle)
|
|
100
108
|
--turborepo Monorepo (Turborepo + apps/packages)
|
|
101
109
|
|
|
110
|
+
${pc.bold("Analyze & Upgrade:")}
|
|
111
|
+
analyze . Detect stack and show recommendations
|
|
112
|
+
analyze --json Output as JSON
|
|
113
|
+
upgrade --plan Show upgrade plan
|
|
114
|
+
upgrade next Upgrade Next.js
|
|
115
|
+
upgrade tailwind Upgrade Tailwind CSS
|
|
116
|
+
|
|
102
117
|
${pc.bold("Options:")}
|
|
103
118
|
-y, --yes Accept defaults
|
|
104
119
|
--no-git Don't initialize Git
|
|
@@ -108,7 +123,8 @@ ${pc.bold("Options:")}
|
|
|
108
123
|
${pc.bold("Examples:")}
|
|
109
124
|
${pc.dim("$")} nimbus create my-landing --landing
|
|
110
125
|
${pc.dim("$")} nimbus create my-app --app
|
|
111
|
-
${pc.dim("$")} nimbus
|
|
126
|
+
${pc.dim("$")} nimbus analyze ./my-project
|
|
127
|
+
${pc.dim("$")} nimbus upgrade --plan
|
|
112
128
|
`)
|
|
113
129
|
}
|
|
114
130
|
|