@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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dawitworku/projectcli",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Interactive project generator (language -> framework -> create).",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",
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 true;
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