create-vee-vue 1.0.0 → 1.0.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.
Files changed (2) hide show
  1. package/bin/index.js +120 -14
  2. package/package.json +2 -1
package/bin/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Command } from "commander";
2
+ import { input, select } from "@inquirer/prompts";
2
3
  import fs from "node:fs";
3
4
  import path from "node:path";
4
5
  import { fileURLToPath } from "node:url";
@@ -7,33 +8,138 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
7
8
 
8
9
  const program = new Command();
9
10
 
11
+ function normalizePackageName(name) {
12
+ return (
13
+ name
14
+ .trim()
15
+ .toLowerCase()
16
+ // 空格和下划线替换为 -
17
+ .replace(/[\s_]+/g, "-")
18
+ // 移除不允许的字符
19
+ .replace(/[^a-z0-9.-]/g, "")
20
+ // 连续的 - 合并为一个
21
+ .replace(/-+/g, "-")
22
+ // 移除开头和结尾的 -
23
+ .replace(/^-+|-+$/g, "")
24
+ // npm 包名不能以 . 开头
25
+ .replace(/^\.+/, "")
26
+ );
27
+ }
28
+
29
+ function updatePackageName(targetDir, projectName) {
30
+ const packageJsonPath = path.join(targetDir, "package.json");
31
+
32
+ // 读取 package.json
33
+ const packageJsonContent = fs.readFileSync(packageJsonPath, "utf-8");
34
+
35
+ // JSON 字符串转换成 JavaScript 对象
36
+ const packageJson = JSON.parse(packageJsonContent);
37
+
38
+ // 修改项目名称
39
+ packageJson.name = projectName;
40
+
41
+ // 将对象转换成 JSON 字符串并写入文件
42
+ fs.writeFileSync(
43
+ packageJsonPath,
44
+ JSON.stringify(packageJson, null, 2) + "\n",
45
+ "utf-8",
46
+ );
47
+ }
48
+
10
49
  program
11
50
  .name("create-vee-vue")
12
51
  .description("Create a Vue 3 project using my template")
13
- .argument("<project-name>", "项目名称")
14
- .action((projectName) => {
15
- // 用户要创建的项目目录
52
+ .version("1.0.0");
53
+
54
+ // 项目名称改为可选参数
55
+ program.argument("[project-name]", "项目名称").action(async (projectName) => {
56
+ try {
57
+ // 1. 用户没有输入项目名称时,弹出输入框
58
+ if (!projectName) {
59
+ projectName = await input({
60
+ message: "Project name:",
61
+ default: "my-vue-app",
62
+ validate(value) {
63
+ if (!value.trim()) {
64
+ return "项目名称不能为空";
65
+ }
66
+
67
+ const packageName = normalizePackageName(value);
68
+
69
+ if (!packageName) {
70
+ return "请输入有效的项目名称";
71
+ }
72
+
73
+ if (packageName.length > 214) {
74
+ return "项目名称不能超过 214 个字符";
75
+ }
76
+
77
+ return true;
78
+ },
79
+ });
80
+ }
81
+
82
+ // 去除项目名称首尾空格
83
+ projectName = projectName.trim();
84
+
85
+ // 生成合法的 npm 包名称
86
+ const packageName = normalizePackageName(projectName);
87
+
88
+ // 2. 选择项目模板
89
+ const templateName = await select({
90
+ message: "Select a template:",
91
+ choices: [
92
+ {
93
+ name: "Vue 3 + TypeScript",
94
+ value: "vue-ts",
95
+ },
96
+ ],
97
+ });
98
+
99
+ // 3. 计算项目路径
16
100
  const targetDir = path.resolve(process.cwd(), projectName);
17
101
 
18
- // CLI 内部的 Vue 模板目录
19
- const templateDir = path.resolve(__dirname, "../templates/vue-ts");
102
+ // 4. 计算模板路径
103
+ const templateDir = path.resolve(__dirname, "../templates", templateName);
20
104
 
21
- // 判断项目目录是否存在
105
+ // 5. 检查项目目录是否存在
22
106
  if (fs.existsSync(targetDir)) {
23
107
  console.error(`目录已存在:${targetDir}`);
24
- process.exit(1);
108
+ process.exitCode = 1;
109
+ return;
110
+ }
111
+
112
+ // 6. 检查模板是否存在
113
+ if (!fs.existsSync(templateDir)) {
114
+ console.error(`模板不存在:${templateDir}`);
115
+ process.exitCode = 1;
116
+ return;
25
117
  }
26
118
 
27
- // 复制整个 Vue 模板
119
+ // 7. 复制模板
120
+ console.log(`Scaffolding project in ${projectName}...`);
121
+
28
122
  fs.cpSync(templateDir, targetDir, {
29
123
  recursive: true,
30
124
  });
31
125
 
32
- console.log("Vue 项目创建成功!");
126
+ updatePackageName(targetDir, packageName);
127
+
33
128
  console.log("");
34
- console.log(`cd ${projectName}`);
35
- console.log("pnpm install");
36
- console.log("pnpm dev");
37
- });
129
+ console.log("Done!");
130
+ console.log("");
131
+ console.log(` cd ${projectName}`);
132
+ console.log(" pnpm install");
133
+ console.log(" pnpm dev");
134
+ } catch (error) {
135
+ if (error.name === "AbortPromptError") {
136
+ console.log("\n取消创建项目");
137
+ return;
138
+ }
139
+
140
+ console.error(error);
141
+ process.exitCode = 1;
142
+ }
143
+ });
38
144
 
39
- program.parse();
145
+ program.parseAsync();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-vee-vue",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "My custom Vue 3 scaffolding",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,6 +14,7 @@
14
14
  "dev": "node ./bin/index.js"
15
15
  },
16
16
  "dependencies": {
17
+ "@inquirer/prompts": "^8.7.5",
17
18
  "commander": "^14.0.0"
18
19
  }
19
20
  }