fwinit 1.0.3 → 1.0.5

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 (2) hide show
  1. package/dist/index.js +152 -10
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -11,31 +11,36 @@ var TEMPLATES = [
11
11
  name: "ASP.NET",
12
12
  alias: ["aspnet", "dotnet", "csharp"],
13
13
  description: "API REST con ASP.NET Core, Clean Architecture y C#",
14
- folder: "ASPNET"
14
+ folder: "ASPNET",
15
+ runtime: "dotnet"
15
16
  },
16
17
  {
17
18
  name: "Express",
18
19
  alias: ["express"],
19
20
  description: "API REST con Express, Prisma, TypeScript y Bun",
20
- folder: "EXPRESS"
21
+ folder: "EXPRESS",
22
+ runtime: "bun"
21
23
  },
22
24
  {
23
25
  name: "Fastify",
24
26
  alias: ["fastify"],
25
27
  description: "API REST con Fastify, Prisma, TypeScript y Bun",
26
- folder: "FASTIFY"
28
+ folder: "FASTIFY",
29
+ runtime: "bun"
27
30
  },
28
31
  {
29
32
  name: "Node.js Vanilla",
30
33
  alias: ["nodejs", "vanilla", "node"],
31
34
  description: "API con Node.js puro, Prisma, TypeScript y tsx",
32
- folder: "NODEJS-VANILLA"
35
+ folder: "NODEJS-VANILLA",
36
+ runtime: "node"
33
37
  },
34
38
  {
35
39
  name: "React Native",
36
40
  alias: ["react-native", "rn", "expo"],
37
41
  description: "App m\xF3vil con React Native, Expo y TypeScript",
38
- folder: "REACT-NATIVE"
42
+ folder: "REACT-NATIVE",
43
+ runtime: "node"
39
44
  }
40
45
  ];
41
46
  function findTemplate(input) {
@@ -208,6 +213,22 @@ async function selectTemplate() {
208
213
  ]);
209
214
  return template;
210
215
  }
216
+ async function selectPackageManager() {
217
+ const { pm } = await inquirer.prompt([
218
+ {
219
+ type: "list",
220
+ name: "pm",
221
+ message: "\xBFQu\xE9 package manager quer\xE9s usar?",
222
+ choices: [
223
+ { name: "pnpm (recomendado)", value: "pnpm" },
224
+ { name: "npm", value: "npm" },
225
+ { name: "bun", value: "bun" }
226
+ ],
227
+ default: "pnpm"
228
+ }
229
+ ]);
230
+ return pm;
231
+ }
211
232
  async function askProjectName() {
212
233
  const { name } = await inquirer.prompt([
213
234
  {
@@ -229,15 +250,67 @@ async function askProjectName() {
229
250
  // src/utils.ts
230
251
  import { existsSync } from "fs";
231
252
  import { resolve } from "path";
253
+ var PM_RUNNER = {
254
+ npm: "npm",
255
+ pnpm: "pnpm",
256
+ bun: "bun"
257
+ };
258
+ var PM_EXEC = {
259
+ npm: "npx",
260
+ pnpm: "pnpm exec",
261
+ bun: "bunx"
262
+ };
263
+ var BUN_SUBCOMMANDS = /* @__PURE__ */ new Set([
264
+ "install",
265
+ "add",
266
+ "remove",
267
+ "update",
268
+ "upgrade",
269
+ "run",
270
+ "x",
271
+ "link",
272
+ "unlink",
273
+ "init",
274
+ "create",
275
+ "pm",
276
+ "outdated",
277
+ "why",
278
+ "publish",
279
+ "prune",
280
+ "rebuild"
281
+ ]);
232
282
  function getProjectPath(name) {
233
283
  return resolve(process.cwd(), name);
234
284
  }
235
285
  function projectExists(name) {
236
286
  return existsSync(getProjectPath(name));
237
287
  }
238
- function printSuccess(projectName, templateName, postInit) {
239
- const installCmd = postInit?.install || "npm install";
240
- const devCmd = postInit?.dev || "npm run dev";
288
+ function resolveCommand(cmd, pm) {
289
+ const tokens = cmd.trim().split(/\s+/);
290
+ const [runner, ...rest] = tokens;
291
+ switch (runner) {
292
+ case "pnpm":
293
+ return [PM_RUNNER[pm], ...rest].join(" ");
294
+ case "npm":
295
+ return [PM_RUNNER[pm], ...rest].join(" ");
296
+ case "bun": {
297
+ if (pm === "bun") return cmd;
298
+ const sub = rest[0];
299
+ if (sub && !BUN_SUBCOMMANDS.has(sub)) {
300
+ return [PM_RUNNER[pm], "run", ...rest].join(" ");
301
+ }
302
+ return [PM_RUNNER[pm], ...rest].join(" ");
303
+ }
304
+ case "npx":
305
+ case "bunx":
306
+ return [PM_EXEC[pm], ...rest].join(" ");
307
+ default:
308
+ return cmd;
309
+ }
310
+ }
311
+ function printSuccess(projectName, templateName, pm, postInit) {
312
+ const installCmd = postInit?.install ? resolveCommand(postInit.install, pm) : `${pm} install`;
313
+ const devCmd = postInit?.dev ? resolveCommand(postInit.dev, pm) : `${pm} run dev`;
241
314
  console.log(`
242
315
  \x1B[32m\u2714\x1B[0m Template descargado
243
316
  \x1B[32m\u2714\x1B[0m Proyecto creado en ./${projectName}
@@ -249,9 +322,60 @@ function printSuccess(projectName, templateName, postInit) {
249
322
  \x1B[36m${devCmd}\x1B[0m
250
323
  `);
251
324
  }
325
+ function adaptScriptToNode(script) {
326
+ let s = script.trim();
327
+ if (/^bun test\b/.test(s)) {
328
+ s = s.replace(/^bun test\b/, "vitest run");
329
+ }
330
+ s = s.replace(/^bun --hot /, "tsx watch ").replace(/^bunx /, "").replace(/^bun /, "tsx ");
331
+ return s;
332
+ }
333
+ async function adaptToNodeRuntime(projectPath) {
334
+ const { readFile: readFile2, writeFile: writeFile2, readdir: readdir2 } = await import("fs/promises");
335
+ const { join: join2 } = await import("path");
336
+ const pkgPath = join2(projectPath, "package.json");
337
+ const pkg = JSON.parse(await readFile2(pkgPath, "utf-8"));
338
+ for (const key of Object.keys(pkg.scripts ?? {})) {
339
+ pkg.scripts[key] = adaptScriptToNode(pkg.scripts[key]);
340
+ }
341
+ pkg.devDependencies ??= {};
342
+ pkg.devDependencies.tsx = "^4.0.0";
343
+ pkg.devDependencies.vitest = "^3.0.0";
344
+ delete pkg.devDependencies["bun-types"];
345
+ await writeFile2(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
346
+ async function walk(dir) {
347
+ const entries = await readdir2(dir, { withFileTypes: true });
348
+ for (const entry of entries) {
349
+ const full = join2(dir, entry.name);
350
+ if (entry.isDirectory()) {
351
+ if (entry.name !== "node_modules") await walk(full);
352
+ } else if (entry.name.endsWith(".test.ts")) {
353
+ const content = await readFile2(full, "utf-8");
354
+ if (content.includes("bun:test")) {
355
+ await writeFile2(full, content.replaceAll('from "bun:test"', 'from "vitest"'));
356
+ }
357
+ }
358
+ }
359
+ }
360
+ const srcDir = join2(projectPath, "src");
361
+ try {
362
+ await walk(srcDir);
363
+ } catch {
364
+ }
365
+ const tsconfigPath = join2(projectPath, "tsconfig.json");
366
+ try {
367
+ const tsconfig = JSON.parse(await readFile2(tsconfigPath, "utf-8"));
368
+ if (tsconfig.compilerOptions?.types?.includes("bun-types")) {
369
+ delete tsconfig.compilerOptions.types;
370
+ await writeFile2(tsconfigPath, JSON.stringify(tsconfig, null, 2) + "\n");
371
+ }
372
+ } catch {
373
+ }
374
+ }
252
375
 
253
376
  // src/index.ts
254
377
  var program = new Command();
378
+ var PACKAGE_MANAGERS = ["npm", "pnpm", "bun"];
255
379
  program.name("fwinit").description("CLI para crear proyectos desde templates").version("1.0.0");
256
380
  program.command("list").description("Mostrar templates disponibles").action(() => {
257
381
  console.log(
@@ -264,11 +388,23 @@ program.command("list").description("Mostrar templates disponibles").action(() =
264
388
  });
265
389
  console.log();
266
390
  });
267
- program.argument("[template]", "Template a usar").argument("[project-name]", "Nombre del proyecto").action(
391
+ program.argument("[template]", "Template a usar").argument("[project-name]", "Nombre del proyecto").option("-p, --pm <package-manager>", "Package manager a usar: npm, pnpm o bun").action(
268
392
  async (templateArg, projectNameArg) => {
269
393
  try {
394
+ const { pm: pmArg } = program.opts();
395
+ if (pmArg && !PACKAGE_MANAGERS.includes(pmArg)) {
396
+ console.error(
397
+ chalk.red(
398
+ `
399
+ \u2716 Package manager "${pmArg}" inv\xE1lido. Us\xE1: npm, pnpm o bun.
400
+ `
401
+ )
402
+ );
403
+ process.exit(1);
404
+ }
270
405
  let template = templateArg ? findTemplate(templateArg) : void 0;
271
406
  let projectName = projectNameArg;
407
+ let pm = pmArg;
272
408
  if (templateArg && !template) {
273
409
  console.error(
274
410
  chalk.red(
@@ -289,6 +425,9 @@ program.argument("[template]", "Template a usar").argument("[project-name]", "No
289
425
  if (!projectName) {
290
426
  projectName = await askProjectName();
291
427
  }
428
+ if (!pm && template.runtime !== "dotnet") {
429
+ pm = await selectPackageManager();
430
+ }
292
431
  if (projectExists(projectName)) {
293
432
  console.error(
294
433
  chalk.red(
@@ -312,6 +451,9 @@ program.argument("[template]", "Template a usar").argument("[project-name]", "No
312
451
  projectName,
313
452
  template.folder
314
453
  );
454
+ if (template.runtime === "bun" && pm && pm !== "bun") {
455
+ await adaptToNodeRuntime(getProjectPath(projectName));
456
+ }
315
457
  await cleanup(tempDir);
316
458
  spinner.succeed("Template descargado");
317
459
  let postInit;
@@ -327,7 +469,7 @@ program.argument("[template]", "Template a usar").argument("[project-name]", "No
327
469
  postInit = tj.postInit;
328
470
  } catch {
329
471
  }
330
- printSuccess(projectName, template.name, postInit);
472
+ printSuccess(projectName, template.name, pm ?? "npm", postInit);
331
473
  } catch (error) {
332
474
  console.error(
333
475
  chalk.red(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fwinit",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "CLI para crear proyectos desde templates",
5
5
  "type": "module",
6
6
  "bin": {