@dawitworku/projectcli 0.1.0 → 0.1.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.md +2 -2
- package/package.json +1 -1
- package/src/index.js +90 -3
package/README.md
CHANGED
|
@@ -9,13 +9,13 @@ Run it as a single command, pick language → framework, and it scaffolds the pr
|
|
|
9
9
|
After you publish this package to npm:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
npx projectcli@latest
|
|
12
|
+
npx @dawitworku/projectcli@latest
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
You can also run non-interactively:
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
npx projectcli@latest --language "TypeScript" --framework "NestJS" --name my-api --pm npm
|
|
18
|
+
npx @dawitworku/projectcli@latest --language "TypeScript" --framework "NestJS" --name my-api --pm npm
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
## Run (dev)
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -25,6 +25,75 @@ const { getLanguages, getFrameworks, getGenerator } = require("./registry");
|
|
|
25
25
|
const { runSteps } = require("./run");
|
|
26
26
|
const { runAdd } = require("./add");
|
|
27
27
|
|
|
28
|
+
const RUST_KEYWORDS = new Set(
|
|
29
|
+
[
|
|
30
|
+
// Strict + reserved keywords (covers the common Cargo failure cases)
|
|
31
|
+
"as",
|
|
32
|
+
"break",
|
|
33
|
+
"const",
|
|
34
|
+
"continue",
|
|
35
|
+
"crate",
|
|
36
|
+
"else",
|
|
37
|
+
"enum",
|
|
38
|
+
"extern",
|
|
39
|
+
"false",
|
|
40
|
+
"fn",
|
|
41
|
+
"for",
|
|
42
|
+
"if",
|
|
43
|
+
"impl",
|
|
44
|
+
"in",
|
|
45
|
+
"let",
|
|
46
|
+
"loop",
|
|
47
|
+
"match",
|
|
48
|
+
"mod",
|
|
49
|
+
"move",
|
|
50
|
+
"mut",
|
|
51
|
+
"pub",
|
|
52
|
+
"ref",
|
|
53
|
+
"return",
|
|
54
|
+
"self",
|
|
55
|
+
"Self",
|
|
56
|
+
"static",
|
|
57
|
+
"struct",
|
|
58
|
+
"super",
|
|
59
|
+
"trait",
|
|
60
|
+
"true",
|
|
61
|
+
"type",
|
|
62
|
+
"unsafe",
|
|
63
|
+
"use",
|
|
64
|
+
"where",
|
|
65
|
+
"while",
|
|
66
|
+
"async",
|
|
67
|
+
"await",
|
|
68
|
+
"dyn",
|
|
69
|
+
"union",
|
|
70
|
+
// Reserved (historical / future)
|
|
71
|
+
"abstract",
|
|
72
|
+
"become",
|
|
73
|
+
"box",
|
|
74
|
+
"do",
|
|
75
|
+
"final",
|
|
76
|
+
"macro",
|
|
77
|
+
"override",
|
|
78
|
+
"priv",
|
|
79
|
+
"try",
|
|
80
|
+
"typeof",
|
|
81
|
+
"unsized",
|
|
82
|
+
"virtual",
|
|
83
|
+
"yield",
|
|
84
|
+
].map(String)
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
function validateProjectNameForSelection({ language, framework }, name) {
|
|
88
|
+
if (language === "Rust" && typeof framework === "string") {
|
|
89
|
+
const usesCargo = framework.toLowerCase().includes("cargo");
|
|
90
|
+
if (usesCargo && RUST_KEYWORDS.has(name)) {
|
|
91
|
+
return `That name is a Rust keyword (${name}). Pick a different name.`;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
|
|
28
97
|
function isSafeProjectName(name) {
|
|
29
98
|
// Avoid path traversal / empty names; keep permissive.
|
|
30
99
|
if (!name) return false;
|
|
@@ -378,7 +447,10 @@ async function main(options = {}) {
|
|
|
378
447
|
if (fs.existsSync(target)) {
|
|
379
448
|
return "That folder already exists. Pick a different name.";
|
|
380
449
|
}
|
|
381
|
-
return
|
|
450
|
+
return validateProjectNameForSelection(
|
|
451
|
+
{ language: state.language, framework: state.framework },
|
|
452
|
+
v
|
|
453
|
+
);
|
|
382
454
|
},
|
|
383
455
|
},
|
|
384
456
|
]);
|
|
@@ -452,6 +524,7 @@ async function main(options = {}) {
|
|
|
452
524
|
|
|
453
525
|
if (action === "cancel") return;
|
|
454
526
|
if (action === "back") {
|
|
527
|
+
state.name = undefined;
|
|
455
528
|
step = "name";
|
|
456
529
|
continue;
|
|
457
530
|
}
|
|
@@ -471,6 +544,11 @@ async function main(options = {}) {
|
|
|
471
544
|
const message = err && err.message ? err.message : String(err);
|
|
472
545
|
console.error(`\nError: ${message}`);
|
|
473
546
|
|
|
547
|
+
const looksLikeNameIssue =
|
|
548
|
+
/cannot be used as a package name|Rust keyword|keyword|Cargo\.toml/i.test(
|
|
549
|
+
message
|
|
550
|
+
);
|
|
551
|
+
|
|
474
552
|
if (args.yes) {
|
|
475
553
|
throw err;
|
|
476
554
|
}
|
|
@@ -481,22 +559,31 @@ async function main(options = {}) {
|
|
|
481
559
|
name: "next",
|
|
482
560
|
message: "What next?",
|
|
483
561
|
choices: [
|
|
484
|
-
{ name: "Try again", value: "retry" },
|
|
562
|
+
{ name: "Try again (same settings)", value: "retry" },
|
|
563
|
+
{ name: "Change project name", value: "name" },
|
|
485
564
|
{ name: "← Back", value: "back" },
|
|
486
565
|
{ name: "Cancel", value: "cancel" },
|
|
487
566
|
],
|
|
488
567
|
pageSize: 6,
|
|
568
|
+
default: looksLikeNameIssue ? "name" : "retry",
|
|
489
569
|
},
|
|
490
570
|
]);
|
|
491
571
|
|
|
492
572
|
if (next === "cancel") return;
|
|
573
|
+
if (next === "name") {
|
|
574
|
+
state.name = undefined;
|
|
575
|
+
step = "name";
|
|
576
|
+
continue;
|
|
577
|
+
}
|
|
493
578
|
if (next === "back") {
|
|
579
|
+
state.name = undefined;
|
|
494
580
|
step = "name";
|
|
495
581
|
continue;
|
|
496
582
|
}
|
|
497
583
|
|
|
498
584
|
// retry
|
|
499
|
-
step = "confirm";
|
|
585
|
+
step = looksLikeNameIssue ? "name" : "confirm";
|
|
586
|
+
if (step === "name") state.name = undefined;
|
|
500
587
|
continue;
|
|
501
588
|
}
|
|
502
589
|
|