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.
- package/README-MDSMITH.md +47 -11
- package/bin/index.js +69 -247
- package/bin/vers/303/243o2.js +997 -0
- package/mdsmith.config.json +2 -1
- package/package.json +4 -1
- package/src/analysis/index.js +149 -0
- package/src/config/index.js +43 -0
- package/src/detectors/index.js +203 -0
- package/src/formatters/index.js +53 -0
- package/src/generators/index.js +27 -0
- package/src/interactive/index.js +95 -0
- package/src/readme/index.js +286 -0
- package/src/scanner/index.js +113 -0
|
@@ -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
|
+
}
|