@gruguy/g-cli 1.0.0

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 +252 -0
  2. package/package.json +19 -0
package/bin/index.js ADDED
@@ -0,0 +1,252 @@
1
+ #!/usr/bin/env node
2
+ const { program } = require("commander");
3
+ const chalk = require("chalk");
4
+ const { spawn } = require("child_process");
5
+ const fs = require("fs");
6
+ const path = require("path");
7
+ const inquirer = require("inquirer");
8
+
9
+ // -------------------------- 自动读取 package.json 版本号 --------------------------
10
+ // 1. 获取当前 CLI 项目的 package.json 路径
11
+ const PACKAGE_JSON_PATH = path.resolve(__dirname, "../package.json");
12
+ // 2. 读取版本号(容错处理)
13
+ let CLI_VERSION = "1.0.0"; // 兜底版本
14
+ try {
15
+ if (fs.existsSync(PACKAGE_JSON_PATH)) {
16
+ const packageJson = JSON.parse(fs.readFileSync(PACKAGE_JSON_PATH, "utf8"));
17
+ CLI_VERSION = packageJson.version || CLI_VERSION;
18
+ }
19
+ } catch (err) {
20
+ console.log(
21
+ chalk.yellow(`⚠️ 读取 package.json 失败,使用默认版本:${CLI_VERSION}`),
22
+ );
23
+ }
24
+
25
+ // -------------------------- 核心配置(自动创建配置文件) --------------------------
26
+ const CONFIG_FILE = path.resolve(
27
+ process.env.HOME || process.env.USERPROFILE,
28
+ ".g-cli-config.json",
29
+ );
30
+ const INIT_DEFAULT_DIR = path.resolve("E:/studio/GIT/Vite+");
31
+
32
+ // -------------------------- 目录配置处理(全自动) --------------------------
33
+ function getDefaultDir() {
34
+ try {
35
+ if (!fs.existsSync(CONFIG_FILE)) {
36
+ fs.writeFileSync(
37
+ CONFIG_FILE,
38
+ JSON.stringify({ defaultDir: INIT_DEFAULT_DIR }, null, 2),
39
+ "utf8",
40
+ );
41
+ return INIT_DEFAULT_DIR;
42
+ }
43
+ const config = JSON.parse(fs.readFileSync(CONFIG_FILE, "utf8"));
44
+ return config.defaultDir || INIT_DEFAULT_DIR;
45
+ } catch (err) {
46
+ console.log(
47
+ chalk.yellow(
48
+ `⚠️ 配置文件处理失败,使用初始默认目录:${INIT_DEFAULT_DIR}`,
49
+ ),
50
+ );
51
+ return INIT_DEFAULT_DIR;
52
+ }
53
+ }
54
+
55
+ function saveDefaultDir(dir) {
56
+ try {
57
+ fs.writeFileSync(
58
+ CONFIG_FILE,
59
+ JSON.stringify({ defaultDir: dir }, null, 2),
60
+ "utf8",
61
+ );
62
+ console.log(chalk.green(`✅ 已将 "${dir}" 设置为新的默认工作目录`));
63
+ } catch (err) {
64
+ console.log(chalk.yellow(`⚠️ 保存默认目录失败:${err.message}`));
65
+ }
66
+ }
67
+
68
+ // -------------------------- 交互式选择目录(通用方法) --------------------------
69
+ async function selectWorkDir() {
70
+ const currentDefaultDir = getDefaultDir();
71
+
72
+ const { useDefault } = await inquirer.prompt([
73
+ {
74
+ type: "confirm",
75
+ name: "useDefault",
76
+ message: chalk.blue("📂 选择项目创建目录:是否使用默认目录?"),
77
+ default: true,
78
+ suffix: chalk.gray(` (${currentDefaultDir})`),
79
+ },
80
+ ]);
81
+
82
+ let targetDir = currentDefaultDir;
83
+ if (!useDefault) {
84
+ const { customDir } = await inquirer.prompt([
85
+ {
86
+ type: "input",
87
+ name: "customDir",
88
+ message: chalk.blue("请输入自定义目录(绝对路径,如 E:/project):"),
89
+ validate: (val) => (val.trim() ? true : "❌ 目录路径不能为空!"),
90
+ },
91
+ ]);
92
+ targetDir = path.resolve(customDir.trim());
93
+
94
+ const { saveAsDefault } = await inquirer.prompt([
95
+ {
96
+ type: "confirm",
97
+ name: "saveAsDefault",
98
+ message: chalk.blue(`是否将 "${targetDir}" 设置为默认工作目录?`),
99
+ default: true,
100
+ suffix: chalk.gray("(下次执行会直接使用该目录)"),
101
+ },
102
+ ]);
103
+ if (saveAsDefault) saveDefaultDir(targetDir);
104
+ else console.log(chalk.gray(`ℹ️ 未将 "${targetDir}" 设置为默认目录`));
105
+ }
106
+
107
+ fs.mkdirSync(targetDir, { recursive: true });
108
+ console.log(chalk.green(`✅ 已确认创建目录:${targetDir}`));
109
+ return targetDir;
110
+ }
111
+
112
+ // -------------------------- 通用命令执行方法 --------------------------
113
+ function runCommand(cmd, cwd) {
114
+ return new Promise((resolve, reject) => {
115
+ process.chdir(cwd);
116
+ console.log(chalk.gray(`🔒 进程已切换到目录:${process.cwd()}`));
117
+
118
+ const [shell, args] =
119
+ process.platform === "win32" ? ["cmd", ["/c", cmd]] : ["sh", ["-c", cmd]];
120
+
121
+ const child = spawn(shell, args, {
122
+ stdio: "inherit",
123
+ shell: true,
124
+ cwd: cwd,
125
+ });
126
+
127
+ child.on("close", (code) =>
128
+ code === 0 ? resolve() : reject(new Error(`执行失败,退出码:${code}`)),
129
+ );
130
+ child.on("error", (err) => reject(new Error(`命令错误:${err.message}`)));
131
+ });
132
+ }
133
+
134
+ // -------------------------- 1. 原有 vp:create 命令 --------------------------
135
+ program
136
+ .command("vp:create")
137
+ .description("创建 vp 项目(支持自定义目录并询问是否设为默认)")
138
+ .option("-w, --work", "直接使用默认目录,跳过交互")
139
+ .action(async (options) => {
140
+ try {
141
+ const targetDir = options.work ? getDefaultDir() : await selectWorkDir();
142
+ console.log(chalk.blue("\n🚀 启动 vp create 交互式创建流程..."));
143
+ await runCommand("vp create", targetDir);
144
+
145
+ console.log(chalk.green("\n🎉 项目创建完成!"));
146
+ console.log(chalk.gray(`📁 项目所在目录:${targetDir}`));
147
+ console.log(
148
+ chalk.gray(`💡 后续操作:cd "${targetDir}/你的项目名" && pnpm install`),
149
+ );
150
+ } catch (err) {
151
+ console.log(chalk.red(`\n❌ 操作失败:${err.message}`));
152
+ process.exit(1);
153
+ }
154
+ });
155
+
156
+ // -------------------------- 2. 新增 pnpm create 命令 --------------------------
157
+ /**
158
+ * 子命令1:pnpm:create(通用 create 命令,支持自定义模板)
159
+ * 使用示例:
160
+ * g pnpm:create vite@latest my-vite-project
161
+ * g pnpm:create vue@latest my-vue-project
162
+ */
163
+ program
164
+ .command("p:create <template> [projectName]")
165
+ .description(
166
+ "执行 pnpm create 命令(如:g pnpm:create vite@latest my-project)",
167
+ )
168
+ .option("-w, --work", "直接使用默认目录,跳过交互")
169
+ .action(async (template, projectName = "pnpm-project", options) => {
170
+ try {
171
+ // 1. 选择创建目录
172
+ const targetDir = options.work ? getDefaultDir() : await selectWorkDir();
173
+ // 2. 拼接完整命令(如:pnpm create vite@latest my-vite-project)
174
+ const createCmd = `pnpm create ${template} ${projectName}`;
175
+ // 3. 执行命令
176
+ console.log(chalk.blue(`\n🚀 执行命令:${createCmd}`));
177
+ await runCommand(createCmd, targetDir);
178
+
179
+ // 4. 成功提示
180
+ const finalPath = path.resolve(targetDir, projectName);
181
+ console.log(chalk.green("\n🎉 pnpm create 项目创建完成!"));
182
+ console.log(chalk.gray(`📁 项目完整路径:${finalPath}`));
183
+ console.log(chalk.gray(`💡 后续操作:cd "${finalPath}" && pnpm install`));
184
+ } catch (err) {
185
+ console.log(chalk.red(`\n❌ 操作失败:${err.message}`));
186
+ process.exit(1);
187
+ }
188
+ });
189
+
190
+ /**
191
+ * 子命令2:快捷创建命令(常用模板,简化输入)
192
+ * 使用示例:
193
+ * g create:vite my-vite-project
194
+ * g create:vue my-vue-project
195
+ */
196
+ // 创建 Vite 项目
197
+ program
198
+ .command("p:create-vite [projectName]")
199
+ .description("快捷创建 Vite 项目(等同于 pnpm create vite@latest)")
200
+ .option("-w, --work", "直接使用默认目录,跳过交互")
201
+ .action(async (projectName = "vite-project", options) => {
202
+ await program.commands
203
+ .find((cmd) => cmd.name() === "pnpm:create")
204
+ .action("vite@latest", projectName, options);
205
+ });
206
+
207
+ // 创建 Vue 项目
208
+ program
209
+ .command("p:create-vue [projectName]")
210
+ .description("快捷创建 Vue 项目(等同于 pnpm create vue@latest)")
211
+ .option("-w, --work", "直接使用默认目录,跳过交互")
212
+ .action(async (projectName = "vue-project", options) => {
213
+ await program.commands
214
+ .find((cmd) => cmd.name() === "pnpm:create")
215
+ .action("vue@latest", projectName, options);
216
+ });
217
+
218
+ // 创建 React 项目
219
+ program
220
+ .command("p:create-react [projectName]")
221
+ .description("快捷创建 React 项目(等同于 pnpm create react-app)")
222
+ .option("-w, --work", "直接使用默认目录,跳过交互")
223
+ .action(async (projectName = "react-project", options) => {
224
+ await program.commands
225
+ .find((cmd) => cmd.name() === "pnpm:create")
226
+ .action("react-app", projectName, options);
227
+ });
228
+
229
+ // -------------------------- 原有 pnpm 快捷命令 --------------------------
230
+ program
231
+ .command("p:install [pkg...]")
232
+ .description("快速执行 pnpm install")
233
+ .action((pkg) => {
234
+ const cmd = `pnpm install ${pkg?.join(" ") || ""}`;
235
+ runCommand(cmd, process.cwd());
236
+ });
237
+
238
+ program
239
+ .command("p:dev")
240
+ .description("快速执行 pnpm run dev")
241
+ .action(() => {
242
+ runCommand("pnpm run dev", process.cwd());
243
+ });
244
+
245
+ // -------------------------- 基础配置 --------------------------
246
+ //版本号自动读取
247
+ program
248
+ .version(CLI_VERSION, "-v, --version", "查看版本")
249
+ .description("自定义 CLI 工具:支持 vp/create/pnpm 全流程命令");
250
+
251
+ program.parse(process.argv);
252
+ if (!process.argv.slice(2).length) program.outputHelp();
package/package.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "@gruguy/g-cli",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "bin/index.js",
6
+ "bin": {
7
+ "g": "./bin/index.js",
8
+ "g-cli": "./bin/index.js"
9
+ },
10
+ "keywords": [],
11
+ "author": "",
12
+ "license": "ISC",
13
+ "packageManager": "pnpm@10.32.1",
14
+ "dependencies": {
15
+ "chalk": "4.1.2",
16
+ "commander": "^14.0.3",
17
+ "inquirer": "8.2.6"
18
+ }
19
+ }