fwinit 1.0.2 → 1.0.4
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/dist/index.js +169 -10
- 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) {
|
|
@@ -117,6 +122,23 @@ async function substituteNodejs(dir, projectName) {
|
|
|
117
122
|
await writeFile(packageJsonPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
118
123
|
} catch {
|
|
119
124
|
}
|
|
125
|
+
const appJsonPath = join(dir, "app.json");
|
|
126
|
+
try {
|
|
127
|
+
const content = await readFile(appJsonPath, "utf-8");
|
|
128
|
+
const app = JSON.parse(content);
|
|
129
|
+
if (app.expo) {
|
|
130
|
+
app.expo.name = projectName;
|
|
131
|
+
app.expo.slug = projectName;
|
|
132
|
+
if (app.expo.scheme) {
|
|
133
|
+
app.expo.scheme = toScheme(projectName);
|
|
134
|
+
}
|
|
135
|
+
await writeFile(appJsonPath, JSON.stringify(app, null, 2) + "\n");
|
|
136
|
+
}
|
|
137
|
+
} catch {
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function toScheme(str) {
|
|
141
|
+
return str.replace(/[-_\s]+/g, "").toLowerCase();
|
|
120
142
|
}
|
|
121
143
|
async function substituteAspNet(dir, projectName) {
|
|
122
144
|
const pascalName = toPascalCase(projectName);
|
|
@@ -191,6 +213,22 @@ async function selectTemplate() {
|
|
|
191
213
|
]);
|
|
192
214
|
return template;
|
|
193
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
|
+
}
|
|
194
232
|
async function askProjectName() {
|
|
195
233
|
const { name } = await inquirer.prompt([
|
|
196
234
|
{
|
|
@@ -212,15 +250,67 @@ async function askProjectName() {
|
|
|
212
250
|
// src/utils.ts
|
|
213
251
|
import { existsSync } from "fs";
|
|
214
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
|
+
]);
|
|
215
282
|
function getProjectPath(name) {
|
|
216
283
|
return resolve(process.cwd(), name);
|
|
217
284
|
}
|
|
218
285
|
function projectExists(name) {
|
|
219
286
|
return existsSync(getProjectPath(name));
|
|
220
287
|
}
|
|
221
|
-
function
|
|
222
|
-
const
|
|
223
|
-
const
|
|
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`;
|
|
224
314
|
console.log(`
|
|
225
315
|
\x1B[32m\u2714\x1B[0m Template descargado
|
|
226
316
|
\x1B[32m\u2714\x1B[0m Proyecto creado en ./${projectName}
|
|
@@ -232,9 +322,60 @@ function printSuccess(projectName, templateName, postInit) {
|
|
|
232
322
|
\x1B[36m${devCmd}\x1B[0m
|
|
233
323
|
`);
|
|
234
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
|
+
}
|
|
235
375
|
|
|
236
376
|
// src/index.ts
|
|
237
377
|
var program = new Command();
|
|
378
|
+
var PACKAGE_MANAGERS = ["npm", "pnpm", "bun"];
|
|
238
379
|
program.name("fwinit").description("CLI para crear proyectos desde templates").version("1.0.0");
|
|
239
380
|
program.command("list").description("Mostrar templates disponibles").action(() => {
|
|
240
381
|
console.log(
|
|
@@ -247,11 +388,23 @@ program.command("list").description("Mostrar templates disponibles").action(() =
|
|
|
247
388
|
});
|
|
248
389
|
console.log();
|
|
249
390
|
});
|
|
250
|
-
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(
|
|
251
392
|
async (templateArg, projectNameArg) => {
|
|
252
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
|
+
}
|
|
253
405
|
let template = templateArg ? findTemplate(templateArg) : void 0;
|
|
254
406
|
let projectName = projectNameArg;
|
|
407
|
+
let pm = pmArg;
|
|
255
408
|
if (templateArg && !template) {
|
|
256
409
|
console.error(
|
|
257
410
|
chalk.red(
|
|
@@ -272,6 +425,9 @@ program.argument("[template]", "Template a usar").argument("[project-name]", "No
|
|
|
272
425
|
if (!projectName) {
|
|
273
426
|
projectName = await askProjectName();
|
|
274
427
|
}
|
|
428
|
+
if (!pm && template.runtime !== "dotnet") {
|
|
429
|
+
pm = await selectPackageManager();
|
|
430
|
+
}
|
|
275
431
|
if (projectExists(projectName)) {
|
|
276
432
|
console.error(
|
|
277
433
|
chalk.red(
|
|
@@ -295,6 +451,9 @@ program.argument("[template]", "Template a usar").argument("[project-name]", "No
|
|
|
295
451
|
projectName,
|
|
296
452
|
template.folder
|
|
297
453
|
);
|
|
454
|
+
if (template.runtime === "bun" && pm && pm !== "bun") {
|
|
455
|
+
await adaptToNodeRuntime(getProjectPath(projectName));
|
|
456
|
+
}
|
|
298
457
|
await cleanup(tempDir);
|
|
299
458
|
spinner.succeed("Template descargado");
|
|
300
459
|
let postInit;
|
|
@@ -310,7 +469,7 @@ program.argument("[template]", "Template a usar").argument("[project-name]", "No
|
|
|
310
469
|
postInit = tj.postInit;
|
|
311
470
|
} catch {
|
|
312
471
|
}
|
|
313
|
-
printSuccess(projectName, template.name, postInit);
|
|
472
|
+
printSuccess(projectName, template.name, pm ?? "npm", postInit);
|
|
314
473
|
} catch (error) {
|
|
315
474
|
console.error(
|
|
316
475
|
chalk.red(
|