mdsmith 1.1.2 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,286 @@
1
+ const fs = require("fs")
2
+ const path = require("path")
3
+ const prompts = require('prompts');
4
+
5
+ const detectors = require("../../src/detectors")
6
+ const scanner = require("../../src/scanner")
7
+ const interactive = require("../../src/interactive")
8
+
9
+ const projectRoot = process.cwd();
10
+
11
+ const i18n = {
12
+ en: {
13
+ // Sections
14
+ projectInfo: "Project Info",
15
+ projectStructure: "Project Structure",
16
+ techStack: "Tech Stack",
17
+ gettingStarted: "Getting Started",
18
+ environmentVariables: "Environment Variables",
19
+ databaseSetup: "Database Setup",
20
+ server: "Server",
21
+
22
+ // Labels
23
+ version: "Version",
24
+ packageManager: "Package Manager",
25
+ type: "Type",
26
+ generatedBy: "Generated by",
27
+
28
+ // Text blocks
29
+ notSpecified: "Not specified",
30
+ createEnvFile: "Create a `.env` file in the project root with the following variables:",
31
+ runMigrations: "Run Prisma migrations:",
32
+ serverRunning: "After starting, the server will run at:",
33
+
34
+ // Project types
35
+ nodeProject: "Node.js Project",
36
+ frontendReact: "React Frontend",
37
+ nextApp: "Next.js Application",
38
+ expressApi: "REST API (Express)",
39
+ typescriptProject: "TypeScript Project"
40
+ },
41
+
42
+ pt: {
43
+ projectInfo: "Informações do Projeto",
44
+ projectStructure: "Estrutura do Projeto",
45
+ techStack: "Tecnologias",
46
+ gettingStarted: "Primeiros Passos",
47
+ environmentVariables: "Variáveis de Ambiente",
48
+ databaseSetup: "Configuração do Banco de Dados",
49
+ server: "Servidor",
50
+
51
+ version: "Versão",
52
+ packageManager: "Gerenciador de Pacotes",
53
+ type: "Tipo",
54
+ generatedBy: "Gerado por",
55
+
56
+ notSpecified: "Não especificado",
57
+ createEnvFile: "Crie um arquivo `.env` na raiz do projeto com as seguintes variáveis:",
58
+ runMigrations: "Execute as migrations do Prisma:",
59
+ serverRunning: "Após iniciar, o servidor estará disponível em:",
60
+
61
+ nodeProject: "Projeto Node.js",
62
+ frontendReact: "Frontend React",
63
+ nextApp: "Aplicação Next.js",
64
+ expressApi: "API REST (Express)",
65
+ typescriptProject: "Projeto TypeScript"
66
+ },
67
+
68
+ es: {
69
+ projectInfo: "Información del Proyecto",
70
+ projectStructure: "Estructura del Proyecto",
71
+ techStack: "Stack Tecnológico",
72
+ gettingStarted: "Primeros Pasos",
73
+ environmentVariables: "Variables de Entorno",
74
+ databaseSetup: "Configuración de Base de Datos",
75
+ server: "Servidor",
76
+
77
+ version: "Versión",
78
+ packageManager: "Administrador de Paquetes",
79
+ type: "Tipo",
80
+ generatedBy: "Generado por",
81
+
82
+ notSpecified: "No especificado",
83
+ createEnvFile: "Crea un archivo `.env` en la raíz del proyecto con las siguientes variables:",
84
+ runMigrations: "Ejecuta las migraciones de Prisma:",
85
+ serverRunning: "Después de iniciar, el servidor estará disponible en:",
86
+
87
+ nodeProject: "Proyecto Node.js",
88
+ frontendReact: "Frontend React",
89
+ nextApp: "Aplicación Next.js",
90
+ expressApi: "API REST (Express)",
91
+ typescriptProject: "Proyecto TypeScript"
92
+ }
93
+ }
94
+
95
+
96
+ async function generateReadme(packageJson, tree, config){
97
+
98
+ const deps = {
99
+ ...packageJson.dependencies,
100
+ ...packageJson.devDependencies
101
+ }
102
+
103
+ const techStack = detectors.detectarTechStack(deps)
104
+ const techSection = gerarTechStackSection(techStack)
105
+
106
+
107
+
108
+
109
+ const envVars = detectors.detectarEnvVars(projectRoot)
110
+ const envSection = gerarEnvSection(envVars)
111
+
112
+ const nomeProjeto = await interactive.buscarNome(packageJson.name);
113
+ const descricaoProjeto = await interactive.buscarDescricao(packageJson.description);
114
+ const idioma = await interactive.escolherLingua()
115
+ const t = i18n[idioma] || i18n.en
116
+
117
+ const packageManager = detectors.detectarPackageManager(projectRoot)
118
+
119
+ const scanData = scanner.scanProjectFiles(projectRoot)
120
+ let port = detectors.detectarPorta(scanData)
121
+
122
+ if (!port) {
123
+ port = await interactive.perguntarPortaManual()
124
+ }
125
+
126
+ const hasPrisma = detectors.detectarPrisma(projectRoot, packageJson)
127
+ const dbSection = hasPrisma ? gerarDatabaseSection(packageManager) : ""
128
+
129
+ const gettingStartedCommands = gerarGettingStarted(
130
+ packageManager,
131
+ packageJson.scripts,
132
+ hasPrisma
133
+ )
134
+
135
+
136
+
137
+ const content = `
138
+ # ${nomeProjeto}
139
+
140
+ ${descricaoProjeto}
141
+
142
+ ## ${config.emojis ? "🔖" : ""} ${t.projectInfo}
143
+ - **${t.version}:** ${packageJson.version || t.notSpecified}
144
+ - **${t.packageManager}:** ${packageManager}
145
+ - **${t.type}:** ${detectarTipoProjeto(packageJson)}
146
+
147
+ ## 🛠 ${t.techStack}
148
+ ${techSection}
149
+
150
+ ## ${config.emojis ? "📁" : ""} ${t.projectStructure}
151
+ \`\`\`
152
+ ${tree}
153
+ \`\`\`
154
+
155
+ ## 🚀 ${t.gettingStarted}
156
+ ${gettingStartedCommands}
157
+
158
+ ## 🔑 ${t.environmentVariables}
159
+ ${t.createEnvFile}
160
+ ${envSection}
161
+
162
+ ## 🗄 ${t.databaseSetup}
163
+ ${t.runMigrations}
164
+ ${dbSection}
165
+
166
+ ${port ? `
167
+ ## 🌐 ${t.server}
168
+
169
+ ${t.serverRunning}
170
+
171
+ http://localhost:${port}
172
+
173
+ ` : ""}
174
+
175
+
176
+ ---
177
+
178
+ ${t.generatedBy} **mdSmith**
179
+ `
180
+
181
+ return content
182
+
183
+ }
184
+
185
+ function getRunCommand(script, packageManager) {
186
+ if (packageManager === "yarn") return `yarn ${script}`
187
+ if (packageManager === "pnpm") return `pnpm ${script}`
188
+ return `npm run ${script}`
189
+ }
190
+
191
+ function detectarTipoProjeto(packageJson) {
192
+ const deps = {
193
+ ...packageJson.dependencies,
194
+ ...packageJson.devDependencies
195
+ }
196
+
197
+ if (deps.react) return "Frontend React"
198
+ if (deps.next) return "Next.js Application"
199
+ if (deps.express) return "API REST (Express)"
200
+ if (deps.typescript) return "Projeto TypeScript"
201
+
202
+ return "Node.js Project"
203
+ }
204
+
205
+
206
+ function gerarEnvSection(vars) {
207
+ if (!vars.length) return ""
208
+
209
+ let section = "\n\n"
210
+
211
+ vars.forEach(v => {
212
+ section += `- ${v}\n`
213
+ })
214
+
215
+ return section + "\n"
216
+ }
217
+
218
+ function gerarDatabaseSection(packageManager) {
219
+ let section = "\n\n"
220
+ section += "\n\n"
221
+ section += "```bash\n"
222
+
223
+ if (packageManager === "npm") {
224
+ section += "npx prisma migrate dev\n"
225
+ section += "npx prisma generate\n"
226
+ } else {
227
+ section += "npx prisma migrate dev\n"
228
+ section += "npx prisma generate\n"
229
+ }
230
+
231
+ section += "```\n\n"
232
+
233
+ return section
234
+ }
235
+
236
+
237
+ function gerarGettingStarted(packageManager = "npm", scripts = {}, hasPrisma) {
238
+ const lines = []
239
+
240
+ lines.push(
241
+ packageManager === "npm"
242
+ ? "npm install"
243
+ : `${packageManager} install`
244
+ )
245
+
246
+ if (hasPrisma) {
247
+ lines.push("npx prisma migrate dev")
248
+ }
249
+
250
+ if (scripts.dev) {
251
+ lines.push(getRunCommand("dev", packageManager))
252
+ } else if (scripts.start) {
253
+ lines.push(getRunCommand("start", packageManager))
254
+ }
255
+
256
+ return `
257
+
258
+ \`\`\`bash
259
+ ${lines.join("\n")}
260
+ \`\`\`
261
+
262
+ `
263
+ }
264
+
265
+ function gerarTechStackSection(stack) {
266
+ if (!stack.length) return ""
267
+
268
+ let section = "\n\n"
269
+
270
+ stack.forEach(tech => {
271
+ section += `- ${tech}\n`
272
+ })
273
+
274
+ return section + "\n"
275
+ }
276
+
277
+
278
+
279
+
280
+ module.exports = {
281
+ generateReadme,
282
+ gerarEnvSection,
283
+ gerarDatabaseSection,
284
+ gerarGettingStarted,
285
+ gerarTechStackSection
286
+ }
@@ -0,0 +1,113 @@
1
+ const fs = require("fs")
2
+ const path = require("path")
3
+
4
+
5
+ function scanDir(dirPath, padding, config) {
6
+ let entries
7
+ try {
8
+ entries = fs.readdirSync(dirPath, { withFileTypes: true })
9
+ .sort((a, b) => {
10
+ if (a.isDirectory() && !b.isDirectory()) return -1
11
+ if (!a.isDirectory() && b.isDirectory()) return 1
12
+ return a.name.localeCompare(b.name)
13
+ })
14
+ } catch {
15
+ return ""
16
+ }
17
+
18
+ let treeContent = ""
19
+
20
+
21
+ for (const entry of entries) {
22
+
23
+ const fullPath = path.join(dirPath, entry.name);
24
+
25
+ if (entry.isDirectory()) {
26
+ if (config.ignore.includes(entry.name)){
27
+ continue
28
+ } else {
29
+ treeContent += `${" ".repeat(padding*2)} 📂 ${entry.name}\n`
30
+ if (config.depth === null || padding < config.depth){
31
+ padding ++
32
+ treeContent += scanDir(fullPath, padding, config)
33
+ padding --
34
+ } else {
35
+ treeContent += `${" ".repeat((padding + 1) * 2)} ··· \n`
36
+ }
37
+ }
38
+ } else {
39
+ if (config.ignore.includes(entry.name)){
40
+ continue
41
+ } else{
42
+ treeContent += `${" ".repeat(padding*2)} 📄 ${entry.name}\n`
43
+ }
44
+ }
45
+ }
46
+
47
+ return treeContent
48
+ }
49
+
50
+ function scanProjectFiles(projectRoot) {
51
+ const result = {
52
+ allFiles: [],
53
+ jsFiles: [],
54
+ tsFiles: [],
55
+ envFiles: [],
56
+ hasDockerfile: false,
57
+ hasPrisma: false,
58
+ hasSrcFolder: false,
59
+ }
60
+
61
+ function walk(dir) {
62
+ let files
63
+ try {
64
+ files = fs.readdirSync(dir)
65
+ } catch {
66
+ return
67
+ }
68
+
69
+ for (const file of files) {
70
+ const fullPath = path.join(dir, file)
71
+
72
+ // ignorar node_modules e .git
73
+ if (
74
+ fullPath.includes("node_modules") ||
75
+ fullPath.includes(".git")
76
+ ) continue
77
+
78
+ let stat
79
+ try {
80
+ stat = fs.lstatSync(fullPath)
81
+
82
+ if (stat.isSymbolicLink()) continue
83
+ } catch {
84
+ continue
85
+ }
86
+
87
+ if (stat.isDirectory()) {
88
+ if (file === "src") {
89
+ result.hasSrcFolder = true
90
+ }
91
+ walk(fullPath)
92
+ } else {
93
+ result.allFiles.push(fullPath)
94
+
95
+ if (file.endsWith(".js")) result.jsFiles.push(fullPath)
96
+ if (file.endsWith(".ts")) result.tsFiles.push(fullPath)
97
+ if (file.startsWith(".env")) result.envFiles.push(fullPath)
98
+
99
+ if (file === "Dockerfile") result.hasDockerfile = true
100
+ if (fullPath.includes("prisma")) result.hasPrisma = true
101
+ }
102
+ }
103
+ }
104
+
105
+ walk(projectRoot)
106
+
107
+ return result
108
+ }
109
+
110
+ module.exports = {
111
+ scanDir,
112
+ scanProjectFiles
113
+ }