fwinit 1.0.0 → 1.0.2

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.
Files changed (3) hide show
  1. package/README.md +55 -6
  2. package/dist/index.js +99 -21
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -5,8 +5,13 @@ CLI para crear proyectos desde templates. Instalás una vez y scaffoldás proyec
5
5
  ## Instalación
6
6
 
7
7
  ```bash
8
+ # pnpm (recomendado)
9
+ pnpm add -g fwinit
10
+
11
+ # npm
8
12
  npm install -g fwinit
9
- # o
13
+
14
+ # bun
10
15
  bun add -g fwinit
11
16
  ```
12
17
 
@@ -61,11 +66,26 @@ fwinit --help
61
66
  ## Desarrollo
62
67
 
63
68
  ```bash
69
+ # pnpm (recomendado)
70
+ pnpm install
71
+ pnpm run build # build a dist/
72
+ pnpm run dev # watch mode
73
+ pnpm run start # ejecutar desde dist/
74
+ pnpm run typecheck # type check
75
+
76
+ # npm
77
+ npm install
78
+ npm run build
79
+ npm run dev
80
+ npm run start
81
+ npm run typecheck
82
+
83
+ # bun
64
84
  bun install
65
- bun run build # build a dist/
66
- bun run dev # watch mode
67
- bun run start # ejecutar desde dist/
68
- bun run typecheck # type check
85
+ bun run build
86
+ bun run dev
87
+ bun run start
88
+ bun run typecheck
69
89
  ```
70
90
 
71
91
  ### Probar localmente
@@ -78,10 +98,39 @@ node dist/index.js fastify mi-api
78
98
  ### Link global para desarrollo
79
99
 
80
100
  ```bash
101
+ # pnpm (recomendado)
102
+ pnpm link --global
103
+
104
+ # npm
105
+ npm link
106
+
107
+ # bun
81
108
  bun link
82
- # ahora `fwinit` está disponible en todo el sistema
83
109
  ```
84
110
 
111
+ Ahora `fwinit` está disponible en todo el sistema.
112
+
113
+ ## Solución a problemas comunes
114
+
115
+ ### pnpm: "Unable to find the global bin directory"
116
+
117
+ pnpm no tiene configurado el directorio global. Corré esto una vez:
118
+
119
+ ```bash
120
+ pnpm setup
121
+ source ~/.bashrc # o reiniciá la terminal
122
+ ```
123
+
124
+ ### bun: "add the global bin folder to $PATH"
125
+
126
+ bun se instaló pero falta agregar su directorio al PATH. Agregalo a tu `.bashrc` o `.zshrc`:
127
+
128
+ ```bash
129
+ export PATH="$HOME/.bun/bin:$PATH"
130
+ ```
131
+
132
+ Después reiniciá la terminal o corré `source ~/.bashrc`.
133
+
85
134
  ## Licencia
86
135
 
87
136
  MIT
package/dist/index.js CHANGED
@@ -47,8 +47,8 @@ function findTemplate(input) {
47
47
 
48
48
  // src/downloader.ts
49
49
  import AdmZip from "adm-zip";
50
- import { mkdir, rm, cp, readdir } from "fs/promises";
51
- import { join } from "path";
50
+ import { mkdir, rm, cp, readdir, readFile, writeFile, rename } from "fs/promises";
51
+ import { join, extname } from "path";
52
52
  import { tmpdir } from "os";
53
53
  import { randomBytes } from "crypto";
54
54
  var GITHUB_REPO = "orlandotellez/fwinit";
@@ -101,6 +101,79 @@ async function cleanTemplate(dir) {
101
101
  async function cleanup(tempDir) {
102
102
  await rm(tempDir, { recursive: true, force: true });
103
103
  }
104
+ async function substituteTemplate(dir, projectName, templateFolder) {
105
+ if (templateFolder === "ASPNET") {
106
+ await substituteAspNet(dir, projectName);
107
+ } else {
108
+ await substituteNodejs(dir, projectName);
109
+ }
110
+ }
111
+ async function substituteNodejs(dir, projectName) {
112
+ const packageJsonPath = join(dir, "package.json");
113
+ try {
114
+ const content = await readFile(packageJsonPath, "utf-8");
115
+ const pkg = JSON.parse(content);
116
+ pkg.name = projectName;
117
+ await writeFile(packageJsonPath, JSON.stringify(pkg, null, 2) + "\n");
118
+ } catch {
119
+ }
120
+ }
121
+ async function substituteAspNet(dir, projectName) {
122
+ const pascalName = toPascalCase(projectName);
123
+ const textExtensions = /* @__PURE__ */ new Set([".cs", ".csproj", ".slnx", ".json", ".http"]);
124
+ const allFiles = await getAllFiles(dir);
125
+ for (const filePath of allFiles) {
126
+ const ext = extname(filePath).toLowerCase();
127
+ if (textExtensions.has(ext)) {
128
+ try {
129
+ const content = await readFile(filePath, "utf-8");
130
+ const replaced = content.replace(/Example/g, pascalName);
131
+ if (replaced !== content) {
132
+ await writeFile(filePath, replaced);
133
+ }
134
+ } catch {
135
+ }
136
+ }
137
+ }
138
+ await renameAll(dir, pascalName);
139
+ }
140
+ async function getAllFiles(dir) {
141
+ const results = [];
142
+ const entries = await readdir(dir, { withFileTypes: true });
143
+ for (const entry of entries) {
144
+ const fullPath = join(dir, entry.name);
145
+ if (entry.isDirectory()) {
146
+ results.push(...await getAllFiles(fullPath));
147
+ } else {
148
+ results.push(fullPath);
149
+ }
150
+ }
151
+ return results;
152
+ }
153
+ async function renameAll(dir, pascalName) {
154
+ const entries = await readdir(dir, { withFileTypes: true });
155
+ for (const entry of entries) {
156
+ const oldPath = join(dir, entry.name);
157
+ if (entry.isDirectory()) {
158
+ await renameAll(oldPath, pascalName);
159
+ }
160
+ }
161
+ const entriesAfter = await readdir(dir, { withFileTypes: true });
162
+ for (const entry of entriesAfter) {
163
+ if (entry.name.includes("Example")) {
164
+ const oldPath = join(dir, entry.name);
165
+ const newName = entry.name.replace(/Example/g, pascalName);
166
+ const newPath = join(dir, newName);
167
+ try {
168
+ await rename(oldPath, newPath);
169
+ } catch {
170
+ }
171
+ }
172
+ }
173
+ }
174
+ function toPascalCase(str) {
175
+ return str.split(/[-_\s]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
176
+ }
104
177
 
105
178
  // src/prompts.ts
106
179
  import inquirer from "inquirer";
@@ -109,7 +182,7 @@ async function selectTemplate() {
109
182
  {
110
183
  type: "list",
111
184
  name: "template",
112
- message: "What project do you want to create?",
185
+ message: "\xBFQu\xE9 proyecto quer\xE9s crear?",
113
186
  choices: TEMPLATES.map((t) => ({
114
187
  name: `${t.name} \u2014 ${t.description}`,
115
188
  value: t
@@ -123,11 +196,11 @@ async function askProjectName() {
123
196
  {
124
197
  type: "input",
125
198
  name: "name",
126
- message: "Project name:",
199
+ message: "Nombre del proyecto:",
127
200
  validate: (input) => {
128
- if (!input.trim()) return "Name cannot be empty";
201
+ if (!input.trim()) return "El nombre no puede estar vac\xEDo";
129
202
  if (!/^[a-zA-Z0-9_-]+$/.test(input)) {
130
- return "Only letters, numbers, hyphens and underscores";
203
+ return "Solo letras, n\xFAmeros, guiones y guiones bajos";
131
204
  }
132
205
  return true;
133
206
  }
@@ -149,10 +222,10 @@ function printSuccess(projectName, templateName, postInit) {
149
222
  const installCmd = postInit?.install || "npm install";
150
223
  const devCmd = postInit?.dev || "npm run dev";
151
224
  console.log(`
152
- \x1B[32m\u2714\x1B[0m Template downloaded
153
- \x1B[32m\u2714\x1B[0m Project created in ./${projectName}
225
+ \x1B[32m\u2714\x1B[0m Template descargado
226
+ \x1B[32m\u2714\x1B[0m Proyecto creado en ./${projectName}
154
227
 
155
- \x1B[1mNext steps:\x1B[0m
228
+ \x1B[1mPr\xF3ximos pasos:\x1B[0m
156
229
 
157
230
  \x1B[36mcd ${projectName}\x1B[0m
158
231
  \x1B[36m${installCmd}\x1B[0m
@@ -162,10 +235,10 @@ function printSuccess(projectName, templateName, postInit) {
162
235
 
163
236
  // src/index.ts
164
237
  var program = new Command();
165
- program.name("fwinit").description("CLI to create projects from templates").version("1.0.0");
166
- program.command("list").description("Show available templates").action(() => {
238
+ program.name("fwinit").description("CLI para crear proyectos desde templates").version("1.0.0");
239
+ program.command("list").description("Mostrar templates disponibles").action(() => {
167
240
  console.log(
168
- chalk.bold("\nAvailable templates:\n")
241
+ chalk.bold("\nTemplates disponibles:\n")
169
242
  );
170
243
  TEMPLATES.forEach((t) => {
171
244
  console.log(
@@ -174,7 +247,7 @@ program.command("list").description("Show available templates").action(() => {
174
247
  });
175
248
  console.log();
176
249
  });
177
- program.argument("[template]", "Template to use").argument("[project-name]", "Project name").action(
250
+ program.argument("[template]", "Template a usar").argument("[project-name]", "Nombre del proyecto").action(
178
251
  async (templateArg, projectNameArg) => {
179
252
  try {
180
253
  let template = templateArg ? findTemplate(templateArg) : void 0;
@@ -183,11 +256,11 @@ program.argument("[template]", "Template to use").argument("[project-name]", "Pr
183
256
  console.error(
184
257
  chalk.red(
185
258
  `
186
- \u2716 Template "${templateArg}" not found.
259
+ \u2716 Template "${templateArg}" no encontrado.
187
260
  `
188
261
  )
189
262
  );
190
- console.log("Available templates:");
263
+ console.log("Templates disponibles:");
191
264
  TEMPLATES.forEach(
192
265
  (t) => console.log(` - ${t.folder.toLowerCase()}`)
193
266
  );
@@ -203,28 +276,33 @@ program.argument("[template]", "Template to use").argument("[project-name]", "Pr
203
276
  console.error(
204
277
  chalk.red(
205
278
  `
206
- \u2716 Directory "${projectName}" already exists.`
279
+ \u2716 El directorio "${projectName}" ya existe.`
207
280
  )
208
281
  );
209
282
  process.exit(1);
210
283
  }
211
284
  const spinner = ora(
212
- `Downloading ${template.name} template...`
285
+ `Descargando template ${template.name}...`
213
286
  ).start();
214
287
  const { tempDir, templatePath } = await downloadAndExtract(template.folder);
215
- spinner.text = "Creating project...";
288
+ spinner.text = "Creando proyecto...";
216
289
  await copyTemplate(
217
290
  templatePath,
218
291
  getProjectPath(projectName)
219
292
  );
293
+ await substituteTemplate(
294
+ getProjectPath(projectName),
295
+ projectName,
296
+ template.folder
297
+ );
220
298
  await cleanup(tempDir);
221
- spinner.succeed("Template downloaded");
299
+ spinner.succeed("Template descargado");
222
300
  let postInit;
223
301
  try {
224
- const { readFile } = await import("fs/promises");
302
+ const { readFile: readFile2 } = await import("fs/promises");
225
303
  const { join: join2 } = await import("path");
226
304
  const tj = JSON.parse(
227
- await readFile(
305
+ await readFile2(
228
306
  join2(getProjectPath(projectName), "template.json"),
229
307
  "utf-8"
230
308
  )
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fwinit",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "CLI para crear proyectos desde templates",
5
5
  "type": "module",
6
6
  "bin": {