@agile-team/robot-cli 2.2.0 → 3.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.
- package/CHANGELOG.md +48 -1
- package/README.md +27 -27
- package/dist/index.js +432 -600
- package/package.json +4 -6
package/dist/index.js
CHANGED
|
@@ -3,15 +3,14 @@ import { readFileSync } from "fs";
|
|
|
3
3
|
import { fileURLToPath } from "url";
|
|
4
4
|
import { dirname, join } from "path";
|
|
5
5
|
import chalk5 from "chalk";
|
|
6
|
-
import
|
|
7
|
-
import inquirer2 from "inquirer";
|
|
6
|
+
import * as p2 from "@clack/prompts";
|
|
8
7
|
import { Command } from "commander";
|
|
9
8
|
|
|
10
9
|
// src/create.ts
|
|
11
10
|
import fs3 from "fs-extra";
|
|
12
11
|
import path3 from "path";
|
|
13
12
|
import chalk3 from "chalk";
|
|
14
|
-
import
|
|
13
|
+
import * as p from "@clack/prompts";
|
|
15
14
|
import ora from "ora";
|
|
16
15
|
import { execSync as execSync2 } from "child_process";
|
|
17
16
|
|
|
@@ -25,7 +24,7 @@ import extract from "extract-zip";
|
|
|
25
24
|
// src/config/templates.config.ts
|
|
26
25
|
var TEMPLATE_CATEGORIES = {
|
|
27
26
|
frontend: {
|
|
28
|
-
name: "\
|
|
27
|
+
name: "\u524D\u7AEF\u9879\u76EE",
|
|
29
28
|
stacks: {
|
|
30
29
|
vue: {
|
|
31
30
|
name: "Vue.js",
|
|
@@ -37,6 +36,7 @@ var TEMPLATE_CATEGORIES = {
|
|
|
37
36
|
name: "Robot Admin \u5B8C\u6574\u7248",
|
|
38
37
|
description: "\u5305\u542B50+\u5B8C\u6574\u793A\u4F8B\u3001\u6743\u9650\u7BA1\u7406\u3001\u56FE\u8868\u7EC4\u4EF6\u3001\u6700\u4F73\u5B9E\u8DF5\u7B49\u7B49",
|
|
39
38
|
repoUrl: "https://github.com/ChenyCHENYU/Robot_Admin",
|
|
39
|
+
giteeUrl: "https://gitee.com/ycyplus163/Robot_Admin",
|
|
40
40
|
features: [
|
|
41
41
|
"Naive UI",
|
|
42
42
|
"Vue Router",
|
|
@@ -64,13 +64,9 @@ var TEMPLATE_CATEGORIES = {
|
|
|
64
64
|
name: "Robot Monorepo",
|
|
65
65
|
description: "bun workspace + Monorepo \u591A\u5305\u7BA1\u7406\u67B6\u6784",
|
|
66
66
|
repoUrl: "https://github.com/ChenyCHENYU/Robot_Admin",
|
|
67
|
+
giteeUrl: "https://gitee.com/ycyplus163/Robot_Admin",
|
|
67
68
|
branch: "monorepo",
|
|
68
|
-
features: [
|
|
69
|
-
"bun workspace",
|
|
70
|
-
"Monorepo",
|
|
71
|
-
"\u591A\u5305\u7BA1\u7406",
|
|
72
|
-
"\u5171\u4EAB\u7EC4\u4EF6"
|
|
73
|
-
],
|
|
69
|
+
features: ["bun workspace", "Monorepo", "\u591A\u5305\u7BA1\u7406", "\u5171\u4EAB\u7EC4\u4EF6"],
|
|
74
70
|
version: "full"
|
|
75
71
|
}
|
|
76
72
|
}
|
|
@@ -82,26 +78,18 @@ var TEMPLATE_CATEGORIES = {
|
|
|
82
78
|
name: "Robot MicroApp \u5FAE\u524D\u7AEF",
|
|
83
79
|
description: "\u57FA\u4E8E MicroApp \u7684\u5FAE\u524D\u7AEF\u67B6\u6784\u65B9\u6848",
|
|
84
80
|
repoUrl: "https://github.com/ChenyCHENYU/Robot_Admin",
|
|
81
|
+
giteeUrl: "https://gitee.com/ycyplus163/Robot_Admin",
|
|
85
82
|
branch: "micro-app",
|
|
86
|
-
features: [
|
|
87
|
-
"MicroApp",
|
|
88
|
-
"\u5FAE\u524D\u7AEF",
|
|
89
|
-
"\u4E3B\u5B50\u5E94\u7528",
|
|
90
|
-
"\u8DEF\u7531\u5171\u4EAB"
|
|
91
|
-
],
|
|
83
|
+
features: ["MicroApp", "\u5FAE\u524D\u7AEF", "\u4E3B\u5B50\u5E94\u7528", "\u8DEF\u7531\u5171\u4EAB"],
|
|
92
84
|
version: "full"
|
|
93
85
|
},
|
|
94
86
|
"robot-module-federation": {
|
|
95
87
|
name: "Robot Module Federation \u6A21\u5757\u8054\u90A6",
|
|
96
88
|
description: "\u57FA\u4E8E Vite Module Federation \u7684\u6A21\u5757\u8054\u90A6\u65B9\u6848",
|
|
97
89
|
repoUrl: "https://github.com/ChenyCHENYU/Robot_Admin",
|
|
90
|
+
giteeUrl: "https://gitee.com/ycyplus163/Robot_Admin",
|
|
98
91
|
branch: "module-federation",
|
|
99
|
-
features: [
|
|
100
|
-
"Module Federation",
|
|
101
|
-
"\u6A21\u5757\u8054\u90A6",
|
|
102
|
-
"Vite",
|
|
103
|
-
"\u8FDC\u7A0B\u6A21\u5757"
|
|
104
|
-
],
|
|
92
|
+
features: ["Module Federation", "\u6A21\u5757\u8054\u90A6", "Vite", "\u8FDC\u7A0B\u6A21\u5757"],
|
|
105
93
|
version: "full"
|
|
106
94
|
}
|
|
107
95
|
}
|
|
@@ -135,7 +123,7 @@ var TEMPLATE_CATEGORIES = {
|
|
|
135
123
|
}
|
|
136
124
|
},
|
|
137
125
|
mobile: {
|
|
138
|
-
name: "\
|
|
126
|
+
name: "\u79FB\u52A8\u7AEF\u9879\u76EE",
|
|
139
127
|
stacks: {
|
|
140
128
|
uniapp: {
|
|
141
129
|
name: "uni-app",
|
|
@@ -147,6 +135,7 @@ var TEMPLATE_CATEGORIES = {
|
|
|
147
135
|
name: "Robot uni-app \u5B8C\u6574\u7248",
|
|
148
136
|
description: "\u591A\u7AEF\u9002\u914D + \u63D2\u4EF6\u5E02\u573A + \u5B8C\u6574\u793A\u4F8B",
|
|
149
137
|
repoUrl: "https://github.com/ChenyCHENYU/Robot_Uniapp",
|
|
138
|
+
giteeUrl: "https://gitee.com/ycyplus163/Robot_uniApp",
|
|
150
139
|
features: ["\u591A\u7AEF\u53D1\u5E03", "uView UI", "\u63D2\u4EF6\u96C6\u6210"],
|
|
151
140
|
version: "full"
|
|
152
141
|
},
|
|
@@ -164,7 +153,7 @@ var TEMPLATE_CATEGORIES = {
|
|
|
164
153
|
}
|
|
165
154
|
},
|
|
166
155
|
backend: {
|
|
167
|
-
name: "\
|
|
156
|
+
name: "\u540E\u7AEF\u9879\u76EE",
|
|
168
157
|
stacks: {
|
|
169
158
|
nestjs: {
|
|
170
159
|
name: "NestJS",
|
|
@@ -212,7 +201,7 @@ var TEMPLATE_CATEGORIES = {
|
|
|
212
201
|
}
|
|
213
202
|
},
|
|
214
203
|
desktop: {
|
|
215
|
-
name: "\
|
|
204
|
+
name: "\u684C\u9762\u7AEF\u9879\u76EE",
|
|
216
205
|
stacks: {
|
|
217
206
|
electron: {
|
|
218
207
|
name: "Electron",
|
|
@@ -354,62 +343,123 @@ async function getCacheStats() {
|
|
|
354
343
|
async function clearCache() {
|
|
355
344
|
await fs.remove(CACHE_DIR);
|
|
356
345
|
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
346
|
+
var TIMEOUT_PRIMARY = 12e4;
|
|
347
|
+
var TIMEOUT_MIRROR = 6e4;
|
|
348
|
+
var MAX_RETRIES = 3;
|
|
349
|
+
function getGitHubMirrors(repoUrl, giteeUrl) {
|
|
350
|
+
const mirrors = [
|
|
351
|
+
repoUrl,
|
|
352
|
+
// 1. 原始 GitHub
|
|
353
|
+
repoUrl.replace("github.com", "hub.gitmirror.com"),
|
|
354
|
+
// 2. gitmirror
|
|
355
|
+
`https://ghproxy.net/${repoUrl}`
|
|
356
|
+
// 3. ghproxy.net
|
|
357
|
+
];
|
|
358
|
+
if (giteeUrl) mirrors.push(giteeUrl);
|
|
359
|
+
return mirrors;
|
|
360
|
+
}
|
|
361
|
+
async function fetchWithRetry(downloadUrl, timeout, retries) {
|
|
362
|
+
let lastError;
|
|
363
|
+
for (let attempt = 1; attempt <= retries; attempt++) {
|
|
365
364
|
try {
|
|
366
|
-
if (spinner) spinner.text = `\u{1F50D} \u8FDE\u63A5\u5230 ${sourceName}...`;
|
|
367
|
-
const downloadUrl = current.endsWith(".zip") ? current : buildDownloadUrl(current, branch);
|
|
368
|
-
if (spinner) spinner.text = `\u{1F4E6} \u4ECE ${sourceName} \u4E0B\u8F7D\u6A21\u677F...`;
|
|
369
365
|
const response = await fetch(downloadUrl, {
|
|
370
|
-
signal: AbortSignal.timeout(
|
|
366
|
+
signal: AbortSignal.timeout(timeout),
|
|
371
367
|
headers: { "User-Agent": "Robot-CLI" }
|
|
372
368
|
});
|
|
373
369
|
if (!response.ok) {
|
|
374
|
-
if (response.status === 404) throw new Error(`\u4ED3\u5E93\u4E0D\u5B58\u5728
|
|
370
|
+
if (response.status === 404) throw new Error(`\u4ED3\u5E93\u4E0D\u5B58\u5728 (404)`);
|
|
375
371
|
throw new Error(`HTTP ${response.status}`);
|
|
376
372
|
}
|
|
373
|
+
return response;
|
|
374
|
+
} catch (error) {
|
|
375
|
+
lastError = error;
|
|
376
|
+
if (lastError.message.includes("404")) throw lastError;
|
|
377
|
+
if (attempt < retries) {
|
|
378
|
+
await new Promise((r) => setTimeout(r, 2e3 * attempt));
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
throw lastError;
|
|
383
|
+
}
|
|
384
|
+
async function tryDownload(repoUrl, branch = "main", spinner, giteeUrl) {
|
|
385
|
+
const url = new URL(repoUrl);
|
|
386
|
+
const host = url.hostname;
|
|
387
|
+
const mirrors = host === "github.com" ? getGitHubMirrors(repoUrl, giteeUrl) : [repoUrl];
|
|
388
|
+
for (let i = 0; i < mirrors.length; i++) {
|
|
389
|
+
const current = mirrors[i];
|
|
390
|
+
const isOriginal = i === 0;
|
|
391
|
+
let sourceName;
|
|
392
|
+
try {
|
|
393
|
+
sourceName = isOriginal ? host : new URL(current.replace(/^(https?:\/\/[^/]+)\/.*/, "$1")).hostname;
|
|
394
|
+
} catch {
|
|
395
|
+
sourceName = `\u955C\u50CF ${i}`;
|
|
396
|
+
}
|
|
397
|
+
try {
|
|
398
|
+
if (spinner) spinner.text = `\u8FDE\u63A5 ${sourceName} ...`;
|
|
399
|
+
const downloadUrl = current.endsWith(".zip") ? current : buildDownloadUrl(current, branch);
|
|
400
|
+
const timeout = isOriginal ? TIMEOUT_PRIMARY : TIMEOUT_MIRROR;
|
|
401
|
+
if (spinner) spinner.text = `\u4ECE ${sourceName} \u4E0B\u8F7D\u6A21\u677F (\u6700\u591A\u91CD\u8BD5${MAX_RETRIES}\u6B21)...`;
|
|
402
|
+
const response = await fetchWithRetry(downloadUrl, timeout, MAX_RETRIES);
|
|
377
403
|
if (spinner) {
|
|
378
404
|
const len = response.headers.get("content-length");
|
|
379
405
|
const sizeInfo = len ? `${(parseInt(len) / 1024 / 1024).toFixed(1)}MB ` : "";
|
|
380
|
-
spinner.text = `\
|
|
406
|
+
spinner.text = `\u4E0B\u8F7D\u4E2D ${sizeInfo}(${sourceName})`;
|
|
381
407
|
}
|
|
382
408
|
return { response, sourceName };
|
|
383
409
|
} catch (error) {
|
|
384
410
|
if (i === mirrors.length - 1) throw error;
|
|
385
|
-
if (spinner) spinner.text =
|
|
411
|
+
if (spinner) spinner.text = `${sourceName} \u4E0D\u53EF\u7528\uFF0C\u5207\u6362\u4E0B\u4E00\u4E2A\u6E90...`;
|
|
386
412
|
await new Promise((r) => setTimeout(r, 1e3));
|
|
387
413
|
}
|
|
388
414
|
}
|
|
389
415
|
throw new Error("\u6240\u6709\u4E0B\u8F7D\u6E90\u5747\u4E0D\u53EF\u7528");
|
|
390
416
|
}
|
|
391
417
|
async function downloadTemplate(template, options = {}) {
|
|
392
|
-
const { spinner, noCache } = options;
|
|
418
|
+
const { spinner, noCache, giteeUrl: optGiteeUrl } = options;
|
|
393
419
|
const branch = template.branch || "main";
|
|
420
|
+
const giteeUrl = optGiteeUrl || template.giteeUrl;
|
|
394
421
|
if (!template?.repoUrl) {
|
|
395
422
|
throw new Error(`\u6A21\u677F\u914D\u7F6E\u65E0\u6548: ${JSON.stringify(template)}`);
|
|
396
423
|
}
|
|
397
424
|
try {
|
|
398
|
-
if (spinner) spinner.text = "\
|
|
425
|
+
if (spinner) spinner.text = "\u5F00\u59CB\u4E0B\u8F7D\u6700\u65B0\u6A21\u677F...";
|
|
399
426
|
const { response, sourceName } = await tryDownload(
|
|
400
427
|
template.repoUrl,
|
|
401
428
|
branch,
|
|
402
|
-
spinner
|
|
429
|
+
spinner,
|
|
430
|
+
giteeUrl
|
|
403
431
|
);
|
|
404
|
-
if (spinner) spinner.text = "\
|
|
432
|
+
if (spinner) spinner.text = "\u4FDD\u5B58\u4E0B\u8F7D\u6587\u4EF6...";
|
|
405
433
|
const timestamp = Date.now();
|
|
406
434
|
const tempZip = path.join(os.tmpdir(), `robot-template-${timestamp}.zip`);
|
|
407
435
|
const tempExtract = path.join(os.tmpdir(), `robot-extract-${timestamp}`);
|
|
408
|
-
const
|
|
409
|
-
|
|
410
|
-
if (
|
|
436
|
+
const contentLength = response.headers.get("content-length");
|
|
437
|
+
const totalSize = contentLength ? parseInt(contentLength, 10) : 0;
|
|
438
|
+
if (totalSize > 0 && response.body && spinner) {
|
|
439
|
+
const reader = response.body.getReader();
|
|
440
|
+
const chunks = [];
|
|
441
|
+
let received = 0;
|
|
442
|
+
while (true) {
|
|
443
|
+
const { done, value } = await reader.read();
|
|
444
|
+
if (done) break;
|
|
445
|
+
chunks.push(value);
|
|
446
|
+
received += value.length;
|
|
447
|
+
const pct = Math.round(received / totalSize * 100);
|
|
448
|
+
const filled = Math.round(pct / 5);
|
|
449
|
+
const bar = "\u2588".repeat(filled) + "\u2591".repeat(20 - filled);
|
|
450
|
+
const sizeMB = (received / 1024 / 1024).toFixed(1);
|
|
451
|
+
const totalMB = (totalSize / 1024 / 1024).toFixed(1);
|
|
452
|
+
spinner.text = `\u4E0B\u8F7D\u4E2D [${bar}] ${pct}% ${sizeMB}MB/${totalMB}MB (${sourceName})`;
|
|
453
|
+
}
|
|
454
|
+
const buffer = Buffer.concat(chunks);
|
|
455
|
+
await fs.writeFile(tempZip, buffer);
|
|
456
|
+
} else {
|
|
457
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
458
|
+
await fs.writeFile(tempZip, buffer);
|
|
459
|
+
}
|
|
460
|
+
if (spinner) spinner.text = "\u89E3\u538B\u6A21\u677F\u6587\u4EF6...";
|
|
411
461
|
await extract(tempZip, { dir: tempExtract });
|
|
412
|
-
if (spinner) spinner.text = "\
|
|
462
|
+
if (spinner) spinner.text = "\u67E5\u627E\u9879\u76EE\u7ED3\u6784...";
|
|
413
463
|
const extractedItems = await fs.readdir(tempExtract);
|
|
414
464
|
const repoName = template.repoUrl.split("/").pop() || "";
|
|
415
465
|
const projectDir = extractedItems.find(
|
|
@@ -421,7 +471,7 @@ async function downloadTemplate(template, options = {}) {
|
|
|
421
471
|
);
|
|
422
472
|
}
|
|
423
473
|
const sourcePath = path.join(tempExtract, projectDir);
|
|
424
|
-
if (spinner) spinner.text = "\
|
|
474
|
+
if (spinner) spinner.text = "\u9A8C\u8BC1\u6A21\u677F\u5B8C\u6574\u6027...";
|
|
425
475
|
if (!fs.existsSync(path.join(sourcePath, "package.json"))) {
|
|
426
476
|
throw new Error("\u6A21\u677F\u7F3A\u5C11 package.json \u6587\u4EF6");
|
|
427
477
|
}
|
|
@@ -429,7 +479,7 @@ async function downloadTemplate(template, options = {}) {
|
|
|
429
479
|
saveToCache(template.repoUrl, sourcePath, branch).catch(() => {
|
|
430
480
|
});
|
|
431
481
|
}
|
|
432
|
-
if (spinner) spinner.text = `\
|
|
482
|
+
if (spinner) spinner.text = `\u6A21\u677F\u4E0B\u8F7D\u5B8C\u6210 (via ${sourceName})`;
|
|
433
483
|
await fs.remove(tempZip).catch(() => {
|
|
434
484
|
});
|
|
435
485
|
return sourcePath;
|
|
@@ -437,9 +487,9 @@ async function downloadTemplate(template, options = {}) {
|
|
|
437
487
|
if (!noCache) {
|
|
438
488
|
const cached = await getCachedTemplate(template.repoUrl);
|
|
439
489
|
if (cached) {
|
|
440
|
-
if (spinner) spinner.text = "\
|
|
490
|
+
if (spinner) spinner.text = "\u7F51\u7EDC\u4E0D\u53EF\u7528\uFF0C\u4F7F\u7528\u7F13\u5B58\u6A21\u677F...";
|
|
441
491
|
console.log();
|
|
442
|
-
console.log(` ${chalk.yellow("\
|
|
492
|
+
console.log(` ${chalk.yellow(" \u6CE8\u610F: \u4F7F\u7528\u7F13\u5B58\u7248\u672C\uFF08\u975E\u6700\u65B0\uFF09")}`);
|
|
443
493
|
return cached;
|
|
444
494
|
}
|
|
445
495
|
}
|
|
@@ -457,9 +507,9 @@ async function downloadTemplate(template, options = {}) {
|
|
|
457
507
|
const isTimeout = errMsg.includes("aborted") || errMsg.includes("timeout") || downloadError.name === "TimeoutError";
|
|
458
508
|
let msg = `\u6A21\u677F\u4E0B\u8F7D\u5931\u8D25: ${errMsg}`;
|
|
459
509
|
if (isTimeout) {
|
|
460
|
-
msg += "\n\n\
|
|
510
|
+
msg += "\n\n \u5EFA\u8BAE:\n 1. \u5F53\u524D\u7F51\u7EDC\u8FDE\u63A5\u8F83\u6162\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\n 2. \u5982\u679C\u5728\u56FD\u5185\uFF0C\u5C1D\u8BD5\u4F7F\u7528\u4EE3\u7406\u6216\u79D1\u5B66\u4E0A\u7F51\n 3. \u4F7F\u7528 robot doctor \u68C0\u67E5\u7F51\u7EDC\u8FDE\u63A5";
|
|
461
511
|
} else if (downloadError.code === "ENOTFOUND") {
|
|
462
|
-
msg += "\n\n\
|
|
512
|
+
msg += "\n\n \u5EFA\u8BAE:\n 1. \u68C0\u67E5\u7F51\u7EDC\u8FDE\u63A5\u662F\u5426\u6B63\u5E38\n 2. \u5982\u679C\u5728\u56FD\u5185\uFF0C\u5C1D\u8BD5\u4F7F\u7528\u4EE3\u7406\n 3. \u7A0D\u540E\u91CD\u8BD5";
|
|
463
513
|
}
|
|
464
514
|
throw new Error(msg);
|
|
465
515
|
}
|
|
@@ -638,9 +688,9 @@ async function copyTemplate(sourcePath, targetPath, spinner) {
|
|
|
638
688
|
throw new Error(`\u6E90\u8DEF\u5F84\u4E0D\u5B58\u5728: ${sourcePath}`);
|
|
639
689
|
}
|
|
640
690
|
await fs2.ensureDir(targetPath);
|
|
641
|
-
if (spinner) spinner.text = "\
|
|
691
|
+
if (spinner) spinner.text = "\u7EDF\u8BA1\u6587\u4EF6\u6570\u91CF...";
|
|
642
692
|
const totalFiles = await countFiles(sourcePath);
|
|
643
|
-
if (spinner) spinner.text = `\
|
|
693
|
+
if (spinner) spinner.text = `\u5F00\u59CB\u590D\u5236 ${totalFiles} \u4E2A\u6587\u4EF6...`;
|
|
644
694
|
let copied = 0;
|
|
645
695
|
const skipDirs = /* @__PURE__ */ new Set([
|
|
646
696
|
"node_modules",
|
|
@@ -664,19 +714,19 @@ async function copyTemplate(sourcePath, targetPath, spinner) {
|
|
|
664
714
|
copied++;
|
|
665
715
|
if (spinner && (copied % 10 === 0 || copied === totalFiles)) {
|
|
666
716
|
const pct = Math.round(copied / totalFiles * 100);
|
|
667
|
-
spinner.text = `\
|
|
717
|
+
spinner.text = `\u590D\u5236\u4E2D ${copied}/${totalFiles} (${pct}%)`;
|
|
668
718
|
}
|
|
669
719
|
}
|
|
670
720
|
}
|
|
671
721
|
}
|
|
672
722
|
await copyDir(sourcePath, targetPath);
|
|
673
|
-
if (spinner) spinner.text = `\
|
|
723
|
+
if (spinner) spinner.text = `\u6587\u4EF6\u590D\u5236\u5B8C\u6210 (${copied} \u4E2A\u6587\u4EF6)`;
|
|
674
724
|
}
|
|
675
725
|
async function installDependencies(projectPath, spinner, packageManager = "npm") {
|
|
676
726
|
try {
|
|
677
727
|
const pkgJson = path2.join(projectPath, "package.json");
|
|
678
728
|
if (!fs2.existsSync(pkgJson)) {
|
|
679
|
-
if (spinner) spinner.text = "\
|
|
729
|
+
if (spinner) spinner.text = "\u8DF3\u8FC7\u4F9D\u8D56\u5B89\u88C5 (\u65E0 package.json)";
|
|
680
730
|
return;
|
|
681
731
|
}
|
|
682
732
|
const cmds = {
|
|
@@ -685,20 +735,20 @@ async function installDependencies(projectPath, spinner, packageManager = "npm")
|
|
|
685
735
|
yarn: "yarn install",
|
|
686
736
|
npm: "npm install"
|
|
687
737
|
};
|
|
688
|
-
if (spinner) spinner.text = `\
|
|
738
|
+
if (spinner) spinner.text = `\u4F7F\u7528 ${packageManager} \u5B89\u88C5\u4F9D\u8D56...`;
|
|
689
739
|
execSync(cmds[packageManager], {
|
|
690
740
|
cwd: projectPath,
|
|
691
741
|
stdio: "ignore",
|
|
692
742
|
timeout: 3e5
|
|
693
743
|
});
|
|
694
|
-
if (spinner) spinner.text = `\
|
|
744
|
+
if (spinner) spinner.text = `\u4F9D\u8D56\u5B89\u88C5\u5B8C\u6210 (${packageManager})`;
|
|
695
745
|
} catch (error) {
|
|
696
|
-
if (spinner) spinner.text = "\
|
|
746
|
+
if (spinner) spinner.text = "\u4F9D\u8D56\u5B89\u88C5\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u5B89\u88C5";
|
|
697
747
|
console.log();
|
|
698
|
-
console.log(chalk2.yellow("\
|
|
748
|
+
console.log(chalk2.yellow("\u81EA\u52A8\u5B89\u88C5\u4F9D\u8D56\u5931\u8D25"));
|
|
699
749
|
console.log(chalk2.dim(` \u9519\u8BEF: ${error.message}`));
|
|
700
750
|
console.log();
|
|
701
|
-
console.log(chalk2.blue("\
|
|
751
|
+
console.log(chalk2.blue("\u8BF7\u624B\u52A8\u5B89\u88C5:"));
|
|
702
752
|
console.log(chalk2.cyan(` cd ${path2.basename(projectPath)}`));
|
|
703
753
|
console.log(chalk2.cyan(` ${packageManager} install`));
|
|
704
754
|
console.log();
|
|
@@ -738,7 +788,7 @@ async function generateProjectStats(projectPath) {
|
|
|
738
788
|
}
|
|
739
789
|
}
|
|
740
790
|
function printProjectStats(stats) {
|
|
741
|
-
console.log(chalk2.blue("\
|
|
791
|
+
console.log(chalk2.blue("\u9879\u76EE\u7EDF\u8BA1:"));
|
|
742
792
|
console.log(` \u6587\u4EF6\u6570\u91CF: ${chalk2.cyan(String(stats.files))} \u4E2A`);
|
|
743
793
|
console.log(` \u76EE\u5F55\u6570\u91CF: ${chalk2.cyan(String(stats.directories))} \u4E2A`);
|
|
744
794
|
console.log(` \u9879\u76EE\u5927\u5C0F: ${chalk2.cyan(formatBytes(stats.size))}`);
|
|
@@ -759,17 +809,9 @@ function formatBytes(bytes) {
|
|
|
759
809
|
}
|
|
760
810
|
|
|
761
811
|
// src/create.ts
|
|
762
|
-
function getVersionLabel(version) {
|
|
763
|
-
const label = VERSION_LABELS[version] || version;
|
|
764
|
-
if (version === "full") return chalk3.green(`[${label}]`);
|
|
765
|
-
if (version === "micro") return chalk3.blue(`[${label}]`);
|
|
766
|
-
return chalk3.yellow(`[${label}]`);
|
|
767
|
-
}
|
|
768
812
|
var STRIP_VERSION_RE = /\s*(完整版|精简版|微服务版)\s*$/;
|
|
769
813
|
async function createProject(projectName, options = {}) {
|
|
770
|
-
|
|
771
|
-
console.log(chalk3.cyan(" Robot CLI - \u5F00\u59CB\u521B\u5EFA\u9879\u76EE"));
|
|
772
|
-
console.log();
|
|
814
|
+
p.intro(chalk3.bgCyan.black(" Robot CLI - \u5F00\u59CB\u521B\u5EFA\u9879\u76EE "));
|
|
773
815
|
let template;
|
|
774
816
|
if (options.from) {
|
|
775
817
|
template = {
|
|
@@ -791,7 +833,7 @@ async function createProject(projectName, options = {}) {
|
|
|
791
833
|
if (options.dryRun) {
|
|
792
834
|
console.log();
|
|
793
835
|
console.log(
|
|
794
|
-
chalk3.yellow("
|
|
836
|
+
chalk3.yellow("Dry Run \u6A21\u5F0F - \u4EE5\u4E0B\u4E3A\u9884\u89C8\u4FE1\u606F\uFF0C\u672A\u5B9E\u9645\u6267\u884C\u4EFB\u4F55\u64CD\u4F5C:")
|
|
795
837
|
);
|
|
796
838
|
console.log();
|
|
797
839
|
console.log(` \u9879\u76EE\u8DEF\u5F84: ${chalk3.cyan(path3.resolve(finalProjectName))}`);
|
|
@@ -823,38 +865,33 @@ async function handleProjectName(projectName, template) {
|
|
|
823
865
|
if (projectName) {
|
|
824
866
|
const v = validateProjectName(projectName);
|
|
825
867
|
if (!v.valid) {
|
|
826
|
-
|
|
827
|
-
v.errors.forEach((e) =>
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
{
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
validate: (input) => {
|
|
835
|
-
const r = validateProjectName(input);
|
|
836
|
-
return r.valid || r.errors[0];
|
|
837
|
-
}
|
|
868
|
+
p.log.error("\u9879\u76EE\u540D\u79F0\u4E0D\u5408\u6CD5:");
|
|
869
|
+
v.errors.forEach((e) => p.log.warn(` ${e}`));
|
|
870
|
+
const newName = await p.text({
|
|
871
|
+
message: "\u8BF7\u8F93\u5165\u65B0\u7684\u9879\u76EE\u540D\u79F0:",
|
|
872
|
+
validate: (input) => {
|
|
873
|
+
if (!input) return "\u9879\u76EE\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A";
|
|
874
|
+
const r = validateProjectName(input);
|
|
875
|
+
return r.valid ? void 0 : r.errors[0];
|
|
838
876
|
}
|
|
839
|
-
|
|
877
|
+
});
|
|
878
|
+
if (p.isCancel(newName)) process.exit(0);
|
|
840
879
|
return newName;
|
|
841
880
|
}
|
|
842
881
|
return projectName;
|
|
843
882
|
}
|
|
844
883
|
const defaultName = generateDefaultProjectName(template);
|
|
845
|
-
const
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
const r = validateProjectName(input);
|
|
854
|
-
return r.valid || r.errors[0];
|
|
855
|
-
}
|
|
884
|
+
const name = await p.text({
|
|
885
|
+
message: "\u8BF7\u8F93\u5165\u9879\u76EE\u540D\u79F0:",
|
|
886
|
+
defaultValue: defaultName,
|
|
887
|
+
placeholder: defaultName,
|
|
888
|
+
validate: (input) => {
|
|
889
|
+
if (!input?.trim()) return "\u9879\u76EE\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A";
|
|
890
|
+
const r = validateProjectName(input);
|
|
891
|
+
return r.valid ? void 0 : r.errors[0];
|
|
856
892
|
}
|
|
857
|
-
|
|
893
|
+
});
|
|
894
|
+
if (p.isCancel(name)) process.exit(0);
|
|
858
895
|
return name;
|
|
859
896
|
}
|
|
860
897
|
function generateDefaultProjectName(template) {
|
|
@@ -869,42 +906,22 @@ async function selectTemplate(templateOption) {
|
|
|
869
906
|
if (all[templateOption]) {
|
|
870
907
|
return { key: templateOption, ...all[templateOption] };
|
|
871
908
|
}
|
|
872
|
-
console.log(chalk3.yellow(`\
|
|
909
|
+
console.log(chalk3.yellow(`\u6A21\u677F "${templateOption}" \u4E0D\u5B58\u5728`));
|
|
873
910
|
console.log();
|
|
874
911
|
}
|
|
875
912
|
return await selectTemplateMethod();
|
|
876
913
|
}
|
|
877
914
|
async function selectTemplateMethod() {
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
{
|
|
889
|
-
name: `${chalk3.cyan(">")} ${chalk3.bold("\u63A8\u8350\u6A21\u677F")} ${chalk3.dim("\u2014 \u57FA\u4E8E\u56E2\u961F\u4F7F\u7528\u9891\u7387\u63A8\u8350\u7684\u70ED\u95E8\u6A21\u677F")}`,
|
|
890
|
-
value: "recommended"
|
|
891
|
-
},
|
|
892
|
-
{
|
|
893
|
-
name: `${chalk3.cyan(">")} ${chalk3.bold("\u5206\u7C7B\u6D4F\u89C8")} ${chalk3.dim("\u2014 \u524D\u7AEF\u3001\u540E\u7AEF\u3001\u79FB\u52A8\u7AEF\u3001\u684C\u9762\u7AEF\u5206\u7C7B")}`,
|
|
894
|
-
value: "category"
|
|
895
|
-
},
|
|
896
|
-
{
|
|
897
|
-
name: `${chalk3.cyan(">")} ${chalk3.bold("\u5173\u952E\u8BCD\u641C\u7D22")} ${chalk3.dim("\u2014 \u6309\u6280\u672F\u6808\u3001\u529F\u80FD\u7279\u6027\u67E5\u627E")}`,
|
|
898
|
-
value: "search"
|
|
899
|
-
},
|
|
900
|
-
{
|
|
901
|
-
name: `${chalk3.cyan(">")} ${chalk3.bold("\u5168\u90E8\u6A21\u677F")} ${chalk3.dim("\u2014 \u67E5\u770B\u6240\u6709\u53EF\u7528\u6A21\u677F")}`,
|
|
902
|
-
value: "all"
|
|
903
|
-
}
|
|
904
|
-
],
|
|
905
|
-
pageSize: 10
|
|
906
|
-
}
|
|
907
|
-
]);
|
|
915
|
+
const selectionMode = await p.select({
|
|
916
|
+
message: "\u6A21\u677F\u9009\u62E9\u65B9\u5F0F:",
|
|
917
|
+
options: [
|
|
918
|
+
{ value: "recommended", label: "\u63A8\u8350\u6A21\u677F", hint: "\u57FA\u4E8E\u56E2\u961F\u4F7F\u7528\u9891\u7387\u63A8\u8350\u7684\u70ED\u95E8\u6A21\u677F" },
|
|
919
|
+
{ value: "category", label: "\u5206\u7C7B\u6D4F\u89C8", hint: "\u524D\u7AEF\u3001\u540E\u7AEF\u3001\u79FB\u52A8\u7AEF\u3001\u684C\u9762\u7AEF\u5206\u7C7B" },
|
|
920
|
+
{ value: "search", label: "\u5173\u952E\u8BCD\u641C\u7D22", hint: "\u6309\u6280\u672F\u6808\u3001\u529F\u80FD\u7279\u6027\u67E5\u627E" },
|
|
921
|
+
{ value: "all", label: "\u5168\u90E8\u6A21\u677F", hint: "\u67E5\u770B\u6240\u6709\u53EF\u7528\u6A21\u677F" }
|
|
922
|
+
]
|
|
923
|
+
});
|
|
924
|
+
if (p.isCancel(selectionMode)) process.exit(0);
|
|
908
925
|
switch (selectionMode) {
|
|
909
926
|
case "recommended":
|
|
910
927
|
return await selectFromRecommended();
|
|
@@ -921,400 +938,258 @@ async function selectTemplateMethod() {
|
|
|
921
938
|
async function selectFromRecommended() {
|
|
922
939
|
const recommended = getRecommendedTemplates();
|
|
923
940
|
if (Object.keys(recommended).length === 0) {
|
|
924
|
-
|
|
941
|
+
p.log.warn("\u6682\u65E0\u63A8\u8350\u6A21\u677F");
|
|
925
942
|
return await selectTemplateMethod();
|
|
926
943
|
}
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
choices.push({
|
|
937
|
-
name: `${chalk3.bold.white(template.name.replace(STRIP_VERSION_RE, ""))} ${ver} - ${chalk3.dim(template.description)}
|
|
938
|
-
${tags}${template.features.length > 3 ? chalk3.dim(` +${template.features.length - 3}more`) : ""}`,
|
|
939
|
-
value: { key, ...template },
|
|
940
|
-
short: template.name
|
|
944
|
+
p.log.info(chalk3.bold("\u63A8\u8350\u6A21\u677F") + chalk3.dim(" \u2014 \u57FA\u4E8E\u56E2\u961F\u4F7F\u7528\u9891\u7387\u548C\u9879\u76EE\u6210\u719F\u5EA6\u63A8\u8350"));
|
|
945
|
+
const options = [];
|
|
946
|
+
for (const [key, template] of Object.entries(recommended)) {
|
|
947
|
+
const ver = VERSION_LABELS[template.version] || template.version;
|
|
948
|
+
const tags = template.features.slice(0, 3).join(", ");
|
|
949
|
+
options.push({
|
|
950
|
+
value: key,
|
|
951
|
+
label: `${template.name.replace(STRIP_VERSION_RE, "")} [${ver}]`,
|
|
952
|
+
hint: `${template.description} | ${tags}`
|
|
941
953
|
});
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
});
|
|
948
|
-
}
|
|
954
|
+
}
|
|
955
|
+
options.push({ value: "back", label: "<- \u8FD4\u56DE\u9009\u62E9\u5176\u4ED6\u65B9\u5F0F" });
|
|
956
|
+
const selected = await p.select({
|
|
957
|
+
message: "\u9009\u62E9\u63A8\u8350\u6A21\u677F:",
|
|
958
|
+
options
|
|
949
959
|
});
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
name: "selectedTemplate",
|
|
955
|
-
message: "\u9009\u62E9\u63A8\u8350\u6A21\u677F:",
|
|
956
|
-
choices,
|
|
957
|
-
pageSize: 15,
|
|
958
|
-
loop: false
|
|
959
|
-
}
|
|
960
|
-
]);
|
|
961
|
-
if (selectedTemplate === "back") return await selectTemplateMethod();
|
|
962
|
-
return selectedTemplate;
|
|
960
|
+
if (p.isCancel(selected)) process.exit(0);
|
|
961
|
+
if (selected === "back") return await selectTemplateMethod();
|
|
962
|
+
const t = recommended[selected];
|
|
963
|
+
return { key: selected, ...t };
|
|
963
964
|
}
|
|
964
965
|
async function selectByCategory() {
|
|
965
966
|
while (true) {
|
|
966
|
-
const
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
const
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
if (
|
|
976
|
-
return
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
const choices = Object.entries(category.stacks).map(([key, s]) => ({
|
|
996
|
-
name: s.name,
|
|
997
|
-
value: key
|
|
998
|
-
}));
|
|
999
|
-
choices.push(
|
|
1000
|
-
{
|
|
1001
|
-
name: chalk3.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),
|
|
1002
|
-
value: "separator",
|
|
1003
|
-
disabled: true
|
|
1004
|
-
},
|
|
1005
|
-
{ name: chalk3.dim("\u2190 \u8FD4\u56DE\u9879\u76EE\u7C7B\u578B\u9009\u62E9"), value: "back_to_category" },
|
|
1006
|
-
{ name: chalk3.dim("\u2190 \u8FD4\u56DE\u6A21\u677F\u9009\u62E9\u65B9\u5F0F"), value: "back_to_method" }
|
|
1007
|
-
);
|
|
1008
|
-
if (choices.length === 4) return choices[0].value;
|
|
1009
|
-
const { stackKey } = await inquirer.prompt([
|
|
1010
|
-
{ type: "list", name: "stackKey", message: "\u8BF7\u9009\u62E9\u6280\u672F\u6808:", choices }
|
|
1011
|
-
]);
|
|
1012
|
-
return stackKey;
|
|
1013
|
-
}
|
|
1014
|
-
async function selectPattern(catKey, stackKey) {
|
|
1015
|
-
if (["back_to_category", "back_to_method"].includes(stackKey))
|
|
1016
|
-
return stackKey;
|
|
1017
|
-
const stack = TEMPLATE_CATEGORIES[catKey].stacks[stackKey];
|
|
1018
|
-
const choices = Object.entries(stack.patterns).map(([key, p]) => ({
|
|
1019
|
-
name: p.name,
|
|
1020
|
-
value: key
|
|
1021
|
-
}));
|
|
1022
|
-
choices.push(
|
|
1023
|
-
{
|
|
1024
|
-
name: chalk3.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),
|
|
1025
|
-
value: "separator",
|
|
1026
|
-
disabled: true
|
|
1027
|
-
},
|
|
1028
|
-
{ name: chalk3.dim("\u2190 \u8FD4\u56DE\u6280\u672F\u6808\u9009\u62E9"), value: "back_to_stack" },
|
|
1029
|
-
{ name: chalk3.dim("\u2190 \u8FD4\u56DE\u9879\u76EE\u7C7B\u578B\u9009\u62E9"), value: "back_to_category" },
|
|
1030
|
-
{ name: chalk3.dim("\u2190 \u8FD4\u56DE\u6A21\u677F\u9009\u62E9\u65B9\u5F0F"), value: "back_to_method" }
|
|
1031
|
-
);
|
|
1032
|
-
if (choices.length === 5) return choices[0].value;
|
|
1033
|
-
const { patternKey } = await inquirer.prompt([
|
|
1034
|
-
{ type: "list", name: "patternKey", message: "\u8BF7\u9009\u62E9\u67B6\u6784\u6A21\u5F0F:", choices }
|
|
1035
|
-
]);
|
|
1036
|
-
return patternKey;
|
|
1037
|
-
}
|
|
1038
|
-
async function selectSpecificTemplate(catKey, stackKey, patternKey) {
|
|
1039
|
-
if (["back_to_stack", "back_to_category", "back_to_method"].includes(patternKey)) {
|
|
1040
|
-
return patternKey;
|
|
1041
|
-
}
|
|
1042
|
-
const templates = getTemplatesByCategory(catKey, stackKey, patternKey);
|
|
1043
|
-
const choices = Object.entries(templates).map(([key, t]) => ({
|
|
1044
|
-
name: `${t.name} - ${chalk3.dim(t.description)}`,
|
|
1045
|
-
value: { key, ...t },
|
|
1046
|
-
short: t.name
|
|
1047
|
-
}));
|
|
1048
|
-
choices.push(
|
|
1049
|
-
{
|
|
1050
|
-
name: chalk3.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),
|
|
1051
|
-
value: "separator",
|
|
1052
|
-
disabled: true
|
|
1053
|
-
},
|
|
1054
|
-
{ name: chalk3.dim("\u2190 \u8FD4\u56DE\u67B6\u6784\u6A21\u5F0F\u9009\u62E9"), value: "back_to_pattern" },
|
|
1055
|
-
{ name: chalk3.dim("\u2190 \u8FD4\u56DE\u6280\u672F\u6808\u9009\u62E9"), value: "back_to_stack" },
|
|
1056
|
-
{ name: chalk3.dim("\u2190 \u8FD4\u56DE\u9879\u76EE\u7C7B\u578B\u9009\u62E9"), value: "back_to_category" },
|
|
1057
|
-
{ name: chalk3.dim("\u2190 \u8FD4\u56DE\u6A21\u677F\u9009\u62E9\u65B9\u5F0F"), value: "back_to_method" }
|
|
1058
|
-
);
|
|
1059
|
-
const { selectedTemplate } = await inquirer.prompt([
|
|
1060
|
-
{
|
|
1061
|
-
type: "list",
|
|
1062
|
-
name: "selectedTemplate",
|
|
1063
|
-
message: "\u8BF7\u9009\u62E9\u6A21\u677F\u7248\u672C:",
|
|
1064
|
-
choices
|
|
967
|
+
const catOptions = Object.entries(TEMPLATE_CATEGORIES).map(([key, c]) => ({
|
|
968
|
+
value: key,
|
|
969
|
+
label: c.name
|
|
970
|
+
}));
|
|
971
|
+
catOptions.push({ value: "back_to_method", label: "<- \u8FD4\u56DE\u6A21\u677F\u9009\u62E9\u65B9\u5F0F" });
|
|
972
|
+
const catKey = await p.select({
|
|
973
|
+
message: "\u8BF7\u9009\u62E9\u9879\u76EE\u7C7B\u578B:",
|
|
974
|
+
options: catOptions
|
|
975
|
+
});
|
|
976
|
+
if (p.isCancel(catKey)) process.exit(0);
|
|
977
|
+
if (catKey === "back_to_method") return await selectTemplateMethod();
|
|
978
|
+
const category = TEMPLATE_CATEGORIES[catKey];
|
|
979
|
+
const stackEntries = Object.entries(category.stacks);
|
|
980
|
+
let stackKey;
|
|
981
|
+
if (stackEntries.length === 1) {
|
|
982
|
+
stackKey = stackEntries[0][0];
|
|
983
|
+
} else {
|
|
984
|
+
const stackOptions = stackEntries.map(([key, s]) => ({
|
|
985
|
+
value: key,
|
|
986
|
+
label: s.name
|
|
987
|
+
}));
|
|
988
|
+
stackOptions.push({ value: "back", label: "<- \u8FD4\u56DE" });
|
|
989
|
+
const sk = await p.select({
|
|
990
|
+
message: "\u8BF7\u9009\u62E9\u6280\u672F\u6808:",
|
|
991
|
+
options: stackOptions
|
|
992
|
+
});
|
|
993
|
+
if (p.isCancel(sk)) process.exit(0);
|
|
994
|
+
if (sk === "back") continue;
|
|
995
|
+
stackKey = sk;
|
|
1065
996
|
}
|
|
1066
|
-
|
|
1067
|
-
|
|
997
|
+
const stack = category.stacks[stackKey];
|
|
998
|
+
const patternEntries = Object.entries(stack.patterns);
|
|
999
|
+
let patternKey;
|
|
1000
|
+
if (patternEntries.length === 1) {
|
|
1001
|
+
patternKey = patternEntries[0][0];
|
|
1002
|
+
} else {
|
|
1003
|
+
const patternOptions = patternEntries.map(([key, pt]) => ({
|
|
1004
|
+
value: key,
|
|
1005
|
+
label: pt.name
|
|
1006
|
+
}));
|
|
1007
|
+
patternOptions.push({ value: "back", label: "<- \u8FD4\u56DE" });
|
|
1008
|
+
const pk = await p.select({
|
|
1009
|
+
message: "\u8BF7\u9009\u62E9\u67B6\u6784\u6A21\u5F0F:",
|
|
1010
|
+
options: patternOptions
|
|
1011
|
+
});
|
|
1012
|
+
if (p.isCancel(pk)) process.exit(0);
|
|
1013
|
+
if (pk === "back") continue;
|
|
1014
|
+
patternKey = pk;
|
|
1015
|
+
}
|
|
1016
|
+
const templates = getTemplatesByCategory(catKey, stackKey, patternKey);
|
|
1017
|
+
const tplOptions = Object.entries(templates).map(([key, t2]) => {
|
|
1018
|
+
const ver = VERSION_LABELS[t2.version] || t2.version;
|
|
1019
|
+
return {
|
|
1020
|
+
value: key,
|
|
1021
|
+
label: `${t2.name} [${ver}]`,
|
|
1022
|
+
hint: t2.description
|
|
1023
|
+
};
|
|
1024
|
+
});
|
|
1025
|
+
tplOptions.push({ value: "back", label: "<- \u8FD4\u56DE", hint: "" });
|
|
1026
|
+
const tplKey = await p.select({
|
|
1027
|
+
message: "\u8BF7\u9009\u62E9\u6A21\u677F\u7248\u672C:",
|
|
1028
|
+
options: tplOptions
|
|
1029
|
+
});
|
|
1030
|
+
if (p.isCancel(tplKey)) process.exit(0);
|
|
1031
|
+
if (tplKey === "back") continue;
|
|
1032
|
+
const t = templates[tplKey];
|
|
1033
|
+
return { key: tplKey, ...t };
|
|
1034
|
+
}
|
|
1068
1035
|
}
|
|
1069
1036
|
async function selectBySearch() {
|
|
1070
1037
|
while (true) {
|
|
1071
|
-
const
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
validate: (input) => input.trim() ? true : "\u5173\u952E\u8BCD\u4E0D\u80FD\u4E3A\u7A7A"
|
|
1077
|
-
}
|
|
1078
|
-
]);
|
|
1038
|
+
const keyword = await p.text({
|
|
1039
|
+
message: "\u8BF7\u8F93\u5165\u641C\u7D22\u5173\u952E\u8BCD (\u540D\u79F0\u3001\u63CF\u8FF0\u3001\u6280\u672F\u6808):",
|
|
1040
|
+
validate: (input) => input?.trim() ? void 0 : "\u5173\u952E\u8BCD\u4E0D\u80FD\u4E3A\u7A7A"
|
|
1041
|
+
});
|
|
1042
|
+
if (p.isCancel(keyword)) return await selectTemplateMethod();
|
|
1079
1043
|
const results = searchTemplates(keyword);
|
|
1080
1044
|
if (Object.keys(results).length === 0) {
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
{ name: "\u91CD\u65B0\u641C\u7D22", value: "retry" },
|
|
1092
|
-
{ name: chalk3.dim("<- \u8FD4\u56DE\u6A21\u677F\u9009\u62E9\u65B9\u5F0F"), value: "back" }
|
|
1093
|
-
]
|
|
1094
|
-
}
|
|
1095
|
-
]);
|
|
1096
|
-
if (action === "retry") continue;
|
|
1097
|
-
return await selectTemplateMethod();
|
|
1045
|
+
p.log.warn(`\u6CA1\u6709\u627E\u5230\u5339\u914D\u7684\u6A21\u677F (\u5173\u952E\u8BCD: "${keyword}")`);
|
|
1046
|
+
const action = await p.select({
|
|
1047
|
+
message: "\u8BF7\u9009\u62E9\u4E0B\u4E00\u6B65\u64CD\u4F5C:",
|
|
1048
|
+
options: [
|
|
1049
|
+
{ value: "retry", label: "\u91CD\u65B0\u641C\u7D22" },
|
|
1050
|
+
{ value: "back", label: "<- \u8FD4\u56DE\u6A21\u677F\u9009\u62E9\u65B9\u5F0F" }
|
|
1051
|
+
]
|
|
1052
|
+
});
|
|
1053
|
+
if (p.isCancel(action) || action === "back") return await selectTemplateMethod();
|
|
1054
|
+
continue;
|
|
1098
1055
|
}
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1056
|
+
p.log.info(`\u5173\u952E\u8BCD: "${keyword}" -- \u627E\u5230 ${Object.keys(results).length} \u4E2A\u5339\u914D\u6A21\u677F`);
|
|
1057
|
+
const options = [];
|
|
1058
|
+
for (const [key, t2] of Object.entries(results)) {
|
|
1059
|
+
const ver = VERSION_LABELS[t2.version] || t2.version;
|
|
1060
|
+
const info = t2.features.slice(0, 3).join(", ");
|
|
1061
|
+
options.push({
|
|
1062
|
+
value: key,
|
|
1063
|
+
label: `${t2.name.replace(STRIP_VERSION_RE, "")} [${ver}]`,
|
|
1064
|
+
hint: `${t2.description} | ${info}`
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
1067
|
+
options.push(
|
|
1068
|
+
{ value: "search_again", label: "\u91CD\u65B0\u641C\u7D22" },
|
|
1069
|
+
{ value: "back_to_mode", label: "<- \u8FD4\u56DE\u6A21\u677F\u9009\u62E9\u65B9\u5F0F" }
|
|
1105
1070
|
);
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
new RegExp(`(${keyword})`, "gi"),
|
|
1110
|
-
chalk3.bgYellow.black("$1")
|
|
1111
|
-
);
|
|
1112
|
-
const ver = getVersionLabel(t.version);
|
|
1113
|
-
const info = t.features.slice(0, 2).join(" \u2022 ");
|
|
1114
|
-
return {
|
|
1115
|
-
name: `${chalk3.bold(hl(t.name.replace(STRIP_VERSION_RE, "")))} ${ver}
|
|
1116
|
-
${chalk3.dim(hl(t.description))}
|
|
1117
|
-
${chalk3.dim(`${info} \u2022 key: ${key}`)}
|
|
1118
|
-
${chalk3.dim("\u2500".repeat(60))}`,
|
|
1119
|
-
value: { key, ...t },
|
|
1120
|
-
short: t.name
|
|
1121
|
-
};
|
|
1071
|
+
const selected = await p.select({
|
|
1072
|
+
message: "\u9009\u62E9\u6A21\u677F:",
|
|
1073
|
+
options
|
|
1122
1074
|
});
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
const { selectedTemplate } = await inquirer.prompt([
|
|
1129
|
-
{
|
|
1130
|
-
type: "list",
|
|
1131
|
-
name: "selectedTemplate",
|
|
1132
|
-
message: "\u9009\u62E9\u6A21\u677F:",
|
|
1133
|
-
choices,
|
|
1134
|
-
pageSize: 15,
|
|
1135
|
-
loop: false
|
|
1136
|
-
}
|
|
1137
|
-
]);
|
|
1138
|
-
if (selectedTemplate === "search_again") continue;
|
|
1139
|
-
if (selectedTemplate === "back_to_mode")
|
|
1140
|
-
return await selectTemplateMethod();
|
|
1141
|
-
return selectedTemplate;
|
|
1075
|
+
if (p.isCancel(selected)) process.exit(0);
|
|
1076
|
+
if (selected === "search_again") continue;
|
|
1077
|
+
if (selected === "back_to_mode") return await selectTemplateMethod();
|
|
1078
|
+
const t = results[selected];
|
|
1079
|
+
return { key: selected, ...t };
|
|
1142
1080
|
}
|
|
1143
1081
|
}
|
|
1144
1082
|
async function selectFromAll() {
|
|
1145
1083
|
const allTemplates = getAllTemplates();
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
console.log(chalk3.dim(` \u5171 ${Object.keys(allTemplates).length} \u4E2A\u6A21\u677F\u53EF\u9009`));
|
|
1149
|
-
console.log();
|
|
1150
|
-
const categorizedChoices = [];
|
|
1084
|
+
p.log.info(chalk3.bold("\u6240\u6709\u53EF\u7528\u6A21\u677F") + chalk3.dim(` -- \u5171 ${Object.keys(allTemplates).length} \u4E2A\u6A21\u677F\u53EF\u9009`));
|
|
1085
|
+
const options = [];
|
|
1151
1086
|
for (const [_catKey, category] of Object.entries(TEMPLATE_CATEGORIES)) {
|
|
1152
|
-
categorizedChoices.push({
|
|
1153
|
-
name: chalk3.yellow.bold(category.name),
|
|
1154
|
-
value: `${_catKey}_header`,
|
|
1155
|
-
disabled: true
|
|
1156
|
-
});
|
|
1157
1087
|
for (const [_sKey, stack] of Object.entries(category.stacks)) {
|
|
1158
1088
|
for (const _pattern of Object.values(stack.patterns)) {
|
|
1159
|
-
for (const [key,
|
|
1160
|
-
const ver =
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
short: t.name
|
|
1166
|
-
});
|
|
1167
|
-
categorizedChoices.push({
|
|
1168
|
-
name: chalk3.dim(" " + "\u2500".repeat(66)),
|
|
1169
|
-
value: `sep_${key}`,
|
|
1170
|
-
disabled: true
|
|
1089
|
+
for (const [key, t2] of Object.entries(_pattern.templates)) {
|
|
1090
|
+
const ver = VERSION_LABELS[t2.version] || t2.version;
|
|
1091
|
+
options.push({
|
|
1092
|
+
value: key,
|
|
1093
|
+
label: `${t2.name.replace(STRIP_VERSION_RE, "")} [${ver}]`,
|
|
1094
|
+
hint: `${category.name} > ${stack.name} | ${t2.description}`
|
|
1171
1095
|
});
|
|
1172
1096
|
}
|
|
1173
1097
|
}
|
|
1174
1098
|
}
|
|
1175
1099
|
}
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
choices: categorizedChoices,
|
|
1186
|
-
pageSize: 25,
|
|
1187
|
-
loop: false
|
|
1188
|
-
}
|
|
1189
|
-
]);
|
|
1190
|
-
if (selectedTemplate === "back_to_mode") return await selectTemplateMethod();
|
|
1191
|
-
return selectedTemplate;
|
|
1100
|
+
options.push({ value: "back_to_mode", label: "<- \u8FD4\u56DE\u6A21\u677F\u9009\u62E9\u65B9\u5F0F" });
|
|
1101
|
+
const selected = await p.select({
|
|
1102
|
+
message: "\u9009\u62E9\u6A21\u677F:",
|
|
1103
|
+
options
|
|
1104
|
+
});
|
|
1105
|
+
if (p.isCancel(selected)) process.exit(0);
|
|
1106
|
+
if (selected === "back_to_mode") return await selectTemplateMethod();
|
|
1107
|
+
const t = allTemplates[selected];
|
|
1108
|
+
return { key: selected, ...t };
|
|
1192
1109
|
}
|
|
1193
1110
|
async function configureProject(options) {
|
|
1194
|
-
|
|
1195
|
-
console.log(chalk3.bold(" \u9879\u76EE\u914D\u7F6E"));
|
|
1196
|
-
console.log();
|
|
1111
|
+
p.log.step(chalk3.bold("\u9879\u76EE\u914D\u7F6E"));
|
|
1197
1112
|
const available = detectPackageManager();
|
|
1198
1113
|
const hasBun = available.includes("bun");
|
|
1199
1114
|
const hasPnpm = available.includes("pnpm");
|
|
1200
|
-
const
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
if (
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
value: "
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
}
|
|
1229
|
-
const config = await inquirer.prompt([
|
|
1230
|
-
{
|
|
1231
|
-
type: "confirm",
|
|
1232
|
-
name: "initGit",
|
|
1233
|
-
message: "\u662F\u5426\u521D\u59CB\u5316 Git \u4ED3\u5E93?",
|
|
1234
|
-
default: true
|
|
1235
|
-
},
|
|
1236
|
-
{
|
|
1237
|
-
type: "confirm",
|
|
1238
|
-
name: "installDeps",
|
|
1239
|
-
message: "\u662F\u5426\u7ACB\u5373\u5B89\u88C5\u4F9D\u8D56?",
|
|
1240
|
-
default: !options.skipInstall
|
|
1241
|
-
},
|
|
1242
|
-
{
|
|
1243
|
-
type: "list",
|
|
1244
|
-
name: "packageManager",
|
|
1245
|
-
message: "\u9009\u62E9\u5305\u7BA1\u7406\u5668:",
|
|
1246
|
-
choices: managerChoices,
|
|
1247
|
-
default: hasBun ? "bun" : hasPnpm ? "pnpm" : "npm",
|
|
1248
|
-
when: (a) => a.installDeps
|
|
1249
|
-
},
|
|
1250
|
-
{
|
|
1251
|
-
type: "input",
|
|
1252
|
-
name: "description",
|
|
1253
|
-
message: "\u9879\u76EE\u63CF\u8FF0 (\u53EF\u9009):",
|
|
1254
|
-
default: ""
|
|
1255
|
-
},
|
|
1256
|
-
{
|
|
1257
|
-
type: "input",
|
|
1258
|
-
name: "author",
|
|
1259
|
-
message: "\u4F5C\u8005 (\u53EF\u9009):",
|
|
1260
|
-
default: getGitUser()
|
|
1261
|
-
},
|
|
1262
|
-
{
|
|
1263
|
-
type: "confirm",
|
|
1264
|
-
name: "confirmConfig",
|
|
1265
|
-
message: "\u786E\u8BA4\u4EE5\u4E0A\u914D\u7F6E?",
|
|
1266
|
-
default: true
|
|
1115
|
+
const initGit = await p.confirm({
|
|
1116
|
+
message: "\u662F\u5426\u521D\u59CB\u5316 Git \u4ED3\u5E93?",
|
|
1117
|
+
initialValue: true
|
|
1118
|
+
});
|
|
1119
|
+
if (p.isCancel(initGit)) process.exit(0);
|
|
1120
|
+
const installDeps = await p.confirm({
|
|
1121
|
+
message: "\u662F\u5426\u7ACB\u5373\u5B89\u88C5\u4F9D\u8D56?",
|
|
1122
|
+
initialValue: !options.skipInstall
|
|
1123
|
+
});
|
|
1124
|
+
if (p.isCancel(installDeps)) process.exit(0);
|
|
1125
|
+
let packageManager = hasBun ? "bun" : hasPnpm ? "pnpm" : "npm";
|
|
1126
|
+
if (installDeps) {
|
|
1127
|
+
const managerOptions = [];
|
|
1128
|
+
if (available.includes("bun"))
|
|
1129
|
+
managerOptions.push({ value: "bun", label: "bun", hint: "\u63A8\u8350 - \u6781\u901F\u5B89\u88C5" });
|
|
1130
|
+
if (available.includes("pnpm"))
|
|
1131
|
+
managerOptions.push({ value: "pnpm", label: "pnpm", hint: "\u63A8\u8350 - \u8282\u7701\u78C1\u76D8\u7A7A\u95F4" });
|
|
1132
|
+
if (available.includes("yarn"))
|
|
1133
|
+
managerOptions.push({ value: "yarn", label: "yarn", hint: "\u517C\u5BB9\u6027\u597D" });
|
|
1134
|
+
if (available.includes("npm"))
|
|
1135
|
+
managerOptions.push({ value: "npm", label: "npm", hint: "Node.js \u5185\u7F6E" });
|
|
1136
|
+
if (managerOptions.length === 0) {
|
|
1137
|
+
managerOptions.push(
|
|
1138
|
+
{ value: "npm", label: "npm" },
|
|
1139
|
+
{ value: "bun", label: "bun" },
|
|
1140
|
+
{ value: "pnpm", label: "pnpm" },
|
|
1141
|
+
{ value: "yarn", label: "yarn" }
|
|
1142
|
+
);
|
|
1267
1143
|
}
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
choices: [
|
|
1276
|
-
{ name: "\u91CD\u65B0\u914D\u7F6E", value: "reconfigure" },
|
|
1277
|
-
{ name: "\u53D6\u6D88\u521B\u5EFA", value: "cancel" }
|
|
1278
|
-
]
|
|
1279
|
-
}
|
|
1280
|
-
]);
|
|
1281
|
-
if (action === "reconfigure") return await configureProject(options);
|
|
1282
|
-
console.log(chalk3.yellow("\u53D6\u6D88\u521B\u5EFA\u9879\u76EE"));
|
|
1283
|
-
process.exit(0);
|
|
1144
|
+
const pm = await p.select({
|
|
1145
|
+
message: "\u9009\u62E9\u5305\u7BA1\u7406\u5668:",
|
|
1146
|
+
options: managerOptions,
|
|
1147
|
+
initialValue: hasBun ? "bun" : hasPnpm ? "pnpm" : "npm"
|
|
1148
|
+
});
|
|
1149
|
+
if (p.isCancel(pm)) process.exit(0);
|
|
1150
|
+
packageManager = pm;
|
|
1284
1151
|
}
|
|
1285
|
-
|
|
1152
|
+
const description = await p.text({
|
|
1153
|
+
message: "\u9879\u76EE\u63CF\u8FF0 (\u53EF\u9009):",
|
|
1154
|
+
defaultValue: "",
|
|
1155
|
+
placeholder: "\u8F93\u5165\u9879\u76EE\u63CF\u8FF0\u6216\u76F4\u63A5\u56DE\u8F66\u8DF3\u8FC7"
|
|
1156
|
+
});
|
|
1157
|
+
if (p.isCancel(description)) process.exit(0);
|
|
1158
|
+
const author = await p.text({
|
|
1159
|
+
message: "\u4F5C\u8005 (\u53EF\u9009):",
|
|
1160
|
+
defaultValue: getGitUser(),
|
|
1161
|
+
placeholder: getGitUser() || "\u8F93\u5165\u4F5C\u8005\u540D"
|
|
1162
|
+
});
|
|
1163
|
+
if (p.isCancel(author)) process.exit(0);
|
|
1164
|
+
return {
|
|
1165
|
+
initGit,
|
|
1166
|
+
installDeps,
|
|
1167
|
+
packageManager,
|
|
1168
|
+
description,
|
|
1169
|
+
author
|
|
1170
|
+
};
|
|
1286
1171
|
}
|
|
1287
1172
|
async function confirmCreation(projectName, template, config) {
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
` \u521D\u59CB\u5316Git: ${config.initGit ? chalk3.green("\u662F") : chalk3.dim("\u5426")}`
|
|
1302
|
-
);
|
|
1303
|
-
console.log(
|
|
1304
|
-
` \u5B89\u88C5\u4F9D\u8D56: ${config.installDeps ? chalk3.green("\u662F") + chalk3.dim(` (${config.packageManager})`) : chalk3.dim("\u5426")}`
|
|
1173
|
+
p.note(
|
|
1174
|
+
[
|
|
1175
|
+
`${chalk3.dim("\u9879\u76EE\u540D\u79F0:")} ${chalk3.cyan(projectName)}`,
|
|
1176
|
+
`${chalk3.dim("\u9009\u62E9\u6A21\u677F:")} ${chalk3.cyan(template.name)}`,
|
|
1177
|
+
`${chalk3.dim("\u6A21\u677F\u63CF\u8FF0:")} ${template.description}`,
|
|
1178
|
+
`${chalk3.dim("\u5305\u542B\u529F\u80FD:")} ${template.features.join(", ") || "\u81EA\u5B9A\u4E49\u6A21\u677F"}`,
|
|
1179
|
+
config.description ? `${chalk3.dim("\u9879\u76EE\u63CF\u8FF0:")} ${config.description}` : "",
|
|
1180
|
+
config.author ? `${chalk3.dim("\u4F5C \u8005:")} ${config.author}` : "",
|
|
1181
|
+
`${chalk3.dim("\u521D\u59CB\u5316Git:")} ${config.initGit ? chalk3.green("\u662F") : "\u5426"}`,
|
|
1182
|
+
`${chalk3.dim("\u5B89\u88C5\u4F9D\u8D56:")} ${config.installDeps ? chalk3.green("\u662F") + ` (${config.packageManager})` : "\u5426"}`,
|
|
1183
|
+
`${chalk3.dim("\u6E90\u7801\u4ED3\u5E93:")} ${template.repoUrl}`
|
|
1184
|
+
].filter(Boolean).join("\n"),
|
|
1185
|
+
"\u9879\u76EE\u521B\u5EFA\u4FE1\u606F\u786E\u8BA4"
|
|
1305
1186
|
);
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
message: "\u786E\u8BA4\u521B\u5EFA\u9879\u76EE?",
|
|
1313
|
-
default: true
|
|
1314
|
-
}
|
|
1315
|
-
]);
|
|
1316
|
-
if (!confirmed) {
|
|
1317
|
-
console.log(chalk3.yellow("\u53D6\u6D88\u521B\u5EFA"));
|
|
1187
|
+
const confirmed = await p.confirm({
|
|
1188
|
+
message: "\u786E\u8BA4\u521B\u5EFA\u9879\u76EE?",
|
|
1189
|
+
initialValue: true
|
|
1190
|
+
});
|
|
1191
|
+
if (p.isCancel(confirmed) || !confirmed) {
|
|
1192
|
+
p.outro(chalk3.yellow("\u53D6\u6D88\u521B\u5EFA"));
|
|
1318
1193
|
process.exit(0);
|
|
1319
1194
|
}
|
|
1320
1195
|
}
|
|
@@ -1323,34 +1198,30 @@ async function executeCreation(projectName, template, config, options) {
|
|
|
1323
1198
|
if (!template?.name)
|
|
1324
1199
|
throw new Error(`\u6A21\u677F\u6570\u636E\u65E0\u6548: ${JSON.stringify(template)}`);
|
|
1325
1200
|
const spinner = ora({
|
|
1326
|
-
text: "\
|
|
1201
|
+
text: "\u51C6\u5907\u521B\u5EFA\u9879\u76EE...",
|
|
1327
1202
|
spinner: "dots",
|
|
1328
1203
|
color: "cyan"
|
|
1329
1204
|
}).start();
|
|
1330
1205
|
let tempPath;
|
|
1331
1206
|
try {
|
|
1332
|
-
spinner.text = "\
|
|
1207
|
+
spinner.text = "\u68C0\u67E5\u9879\u76EE\u76EE\u5F55...";
|
|
1333
1208
|
const projectPath = path3.resolve(projectName);
|
|
1334
1209
|
if (fs3.existsSync(projectPath)) {
|
|
1335
1210
|
spinner.stop();
|
|
1336
|
-
|
|
1337
|
-
const
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
}
|
|
1344
|
-
]);
|
|
1345
|
-
if (!overwrite) {
|
|
1346
|
-
console.log(chalk3.yellow("\u274C \u53D6\u6D88\u521B\u5EFA"));
|
|
1211
|
+
p.log.warn("\u9879\u76EE\u76EE\u5F55\u5DF2\u5B58\u5728");
|
|
1212
|
+
const overwrite = await p.confirm({
|
|
1213
|
+
message: "\u76EE\u5F55\u5DF2\u5B58\u5728\uFF0C\u662F\u5426\u8986\u76D6?",
|
|
1214
|
+
initialValue: false
|
|
1215
|
+
});
|
|
1216
|
+
if (p.isCancel(overwrite) || !overwrite) {
|
|
1217
|
+
p.outro(chalk3.yellow("\u53D6\u6D88\u521B\u5EFA"));
|
|
1347
1218
|
process.exit(0);
|
|
1348
1219
|
}
|
|
1349
|
-
spinner.start("\
|
|
1220
|
+
spinner.start("\u6E05\u7406\u73B0\u6709\u76EE\u5F55...");
|
|
1350
1221
|
await fs3.remove(projectPath);
|
|
1351
|
-
spinner.text = "\
|
|
1222
|
+
spinner.text = "\u51C6\u5907\u521B\u5EFA\u65B0\u76EE\u5F55...";
|
|
1352
1223
|
}
|
|
1353
|
-
spinner.text = "\
|
|
1224
|
+
spinner.text = "\u4E0B\u8F7D\u6700\u65B0\u6A21\u677F...";
|
|
1354
1225
|
try {
|
|
1355
1226
|
tempPath = await downloadTemplate(template, {
|
|
1356
1227
|
spinner,
|
|
@@ -1361,63 +1232,52 @@ async function executeCreation(projectName, template, config, options) {
|
|
|
1361
1232
|
} catch (error) {
|
|
1362
1233
|
spinner.fail("\u6A21\u677F\u4E0B\u8F7D\u5931\u8D25");
|
|
1363
1234
|
console.log();
|
|
1364
|
-
console.log(chalk3.
|
|
1365
|
-
console.log(chalk3.dim(` ${error.message}`));
|
|
1235
|
+
console.log(chalk3.dim(` ${error.message}`));
|
|
1366
1236
|
console.log();
|
|
1367
|
-
|
|
1237
|
+
return;
|
|
1368
1238
|
}
|
|
1369
1239
|
await copyTemplate(tempPath, projectPath, spinner);
|
|
1370
|
-
spinner.text = "\
|
|
1240
|
+
spinner.text = "\u5904\u7406\u9879\u76EE\u914D\u7F6E...";
|
|
1371
1241
|
await processProjectConfig(projectPath, projectName, template, config);
|
|
1372
1242
|
if (config.initGit) {
|
|
1373
|
-
spinner.text = "\
|
|
1243
|
+
spinner.text = "\u521D\u59CB\u5316 Git \u4ED3\u5E93...";
|
|
1374
1244
|
initializeGitRepository(projectPath);
|
|
1375
1245
|
}
|
|
1376
1246
|
if (config.installDeps) {
|
|
1377
|
-
spinner.text = `\
|
|
1247
|
+
spinner.text = `\u4F7F\u7528 ${config.packageManager} \u5B89\u88C5\u4F9D\u8D56...`;
|
|
1378
1248
|
await installDependencies(projectPath, spinner, config.packageManager);
|
|
1379
1249
|
}
|
|
1380
1250
|
if (tempPath) {
|
|
1381
|
-
spinner.text = "\
|
|
1251
|
+
spinner.text = "\u6E05\u7406\u4E34\u65F6\u6587\u4EF6...";
|
|
1382
1252
|
await fs3.remove(tempPath).catch(() => {
|
|
1383
1253
|
});
|
|
1384
1254
|
}
|
|
1385
|
-
spinner.succeed(chalk3.green("\
|
|
1386
|
-
console.log();
|
|
1387
|
-
console.log(chalk3.green("\u9879\u76EE\u521B\u5EFA\u5B8C\u6210!"));
|
|
1388
|
-
console.log();
|
|
1389
|
-
console.log(chalk3.blue("\u9879\u76EE\u4FE1\u606F:"));
|
|
1390
|
-
console.log(` \u4F4D\u7F6E: ${chalk3.cyan(projectPath)}`);
|
|
1391
|
-
console.log(` \u6A21\u677F: ${chalk3.cyan(template.name)}`);
|
|
1392
|
-
console.log(
|
|
1393
|
-
` Git\u4ED3\u5E93: ${config.initGit ? chalk3.green("\u5DF2\u521D\u59CB\u5316") : chalk3.dim("\u672A\u521D\u59CB\u5316")}`
|
|
1394
|
-
);
|
|
1395
|
-
console.log(
|
|
1396
|
-
` \u4F9D\u8D56\u5B89\u88C5: ${config.installDeps ? chalk3.green("\u5DF2\u5B8C\u6210") : chalk3.dim("\u9700\u624B\u52A8\u5B89\u88C5")}`
|
|
1397
|
-
);
|
|
1398
|
-
console.log();
|
|
1399
|
-
console.log(chalk3.blue("\u5FEB\u901F\u5F00\u59CB:"));
|
|
1400
|
-
console.log(chalk3.cyan(` cd ${projectName}`));
|
|
1255
|
+
spinner.succeed(chalk3.green("\u9879\u76EE\u521B\u5EFA\u6210\u529F!"));
|
|
1401
1256
|
const pm = config.packageManager || "bun";
|
|
1402
|
-
if (!config.installDeps) {
|
|
1403
|
-
console.log(chalk3.cyan(` ${pm} install`));
|
|
1404
|
-
}
|
|
1405
1257
|
const cmd = getStartCommand(template, pm);
|
|
1406
|
-
|
|
1407
|
-
if (pm
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
chalk3.dim("
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1258
|
+
const steps = [`cd ${projectName}`];
|
|
1259
|
+
if (!config.installDeps) steps.push(`${pm} install`);
|
|
1260
|
+
if (cmd) steps.push(cmd);
|
|
1261
|
+
p.note(
|
|
1262
|
+
[
|
|
1263
|
+
`${chalk3.dim("\u4F4D\u7F6E:")} ${chalk3.cyan(projectPath)}`,
|
|
1264
|
+
`${chalk3.dim("\u6A21\u677F:")} ${chalk3.cyan(template.name)}`,
|
|
1265
|
+
`${chalk3.dim("Git:")} ${config.initGit ? chalk3.green("\u5DF2\u521D\u59CB\u5316") : "\u672A\u521D\u59CB\u5316"}`,
|
|
1266
|
+
`${chalk3.dim("\u4F9D\u8D56:")} ${config.installDeps ? chalk3.green("\u5DF2\u5B8C\u6210") : "\u9700\u624B\u52A8\u5B89\u88C5"}`,
|
|
1267
|
+
"",
|
|
1268
|
+
chalk3.bold("\u5FEB\u901F\u5F00\u59CB:"),
|
|
1269
|
+
...steps.map((s) => ` ${chalk3.cyan(s)}`)
|
|
1270
|
+
].join("\n"),
|
|
1271
|
+
"\u9879\u76EE\u521B\u5EFA\u5B8C\u6210"
|
|
1272
|
+
);
|
|
1273
|
+
const statsSpinner = ora("\u7EDF\u8BA1\u9879\u76EE\u4FE1\u606F...").start();
|
|
1415
1274
|
const stats = await generateProjectStats(projectPath);
|
|
1416
|
-
|
|
1275
|
+
statsSpinner.stop();
|
|
1417
1276
|
if (stats) {
|
|
1418
1277
|
printProjectStats(stats);
|
|
1419
1278
|
console.log();
|
|
1420
1279
|
}
|
|
1280
|
+
p.outro(chalk3.green("Happy coding!"));
|
|
1421
1281
|
} catch (error) {
|
|
1422
1282
|
if (tempPath) await fs3.remove(tempPath).catch(() => {
|
|
1423
1283
|
});
|
|
@@ -1467,7 +1327,7 @@ function initializeGitRepository(projectPath) {
|
|
|
1467
1327
|
stdio: "ignore"
|
|
1468
1328
|
});
|
|
1469
1329
|
} catch {
|
|
1470
|
-
console.log(chalk3.yellow("
|
|
1330
|
+
console.log(chalk3.yellow("Git \u4E0D\u53EF\u7528\uFF0C\u8DF3\u8FC7\u4ED3\u5E93\u521D\u59CB\u5316"));
|
|
1471
1331
|
}
|
|
1472
1332
|
}
|
|
1473
1333
|
function getStartCommand(template, pm) {
|
|
@@ -1538,9 +1398,9 @@ async function runDoctor(options = {}) {
|
|
|
1538
1398
|
detail: cacheStats.count > 0 ? `${cacheStats.count} \u4E2A\u6A21\u677F (${formatBytes(cacheStats.totalSize)})` : "\u7A7A"
|
|
1539
1399
|
});
|
|
1540
1400
|
const icons = {
|
|
1541
|
-
ok: chalk4.green("
|
|
1542
|
-
warn: chalk4.yellow("
|
|
1543
|
-
error: chalk4.red("
|
|
1401
|
+
ok: chalk4.green("[OK]"),
|
|
1402
|
+
warn: chalk4.yellow("[!!]"),
|
|
1403
|
+
error: chalk4.red("[NO]")
|
|
1544
1404
|
};
|
|
1545
1405
|
for (const r of results) {
|
|
1546
1406
|
const icon = icons[r.status];
|
|
@@ -1550,11 +1410,11 @@ async function runDoctor(options = {}) {
|
|
|
1550
1410
|
const hasError = results.some((r) => r.status === "error");
|
|
1551
1411
|
const hasWarn = results.some((r) => r.status === "warn");
|
|
1552
1412
|
if (hasError) {
|
|
1553
|
-
console.log(chalk4.red(" \u8BCA\u65AD\u7ED3\u679C: \u73AF\u5883\u5B58\u5728\u95EE\u9898\uFF0C\u8BF7\u4FEE\u590D\u4E0A\u8FF0\u9519\u8BEF
|
|
1413
|
+
console.log(chalk4.red(" \u8BCA\u65AD\u7ED3\u679C: \u73AF\u5883\u5B58\u5728\u95EE\u9898\uFF0C\u8BF7\u4FEE\u590D\u4E0A\u8FF0\u9519\u8BEF"));
|
|
1554
1414
|
} else if (hasWarn) {
|
|
1555
|
-
console.log(chalk4.yellow(" \u8BCA\u65AD\u7ED3\u679C: \u73AF\u5883\u57FA\u672C\u6B63\u5E38\uFF0C\u90E8\u5206\u7EC4\u4EF6\u7F3A\u5931
|
|
1415
|
+
console.log(chalk4.yellow(" \u8BCA\u65AD\u7ED3\u679C: \u73AF\u5883\u57FA\u672C\u6B63\u5E38\uFF0C\u90E8\u5206\u7EC4\u4EF6\u7F3A\u5931"));
|
|
1556
1416
|
} else {
|
|
1557
|
-
console.log(chalk4.green(" \u8BCA\u65AD\u7ED3\u679C: \u73AF\u5883\u5065\u5EB7
|
|
1417
|
+
console.log(chalk4.green(" \u8BCA\u65AD\u7ED3\u679C: \u73AF\u5883\u5065\u5EB7"));
|
|
1558
1418
|
}
|
|
1559
1419
|
console.log();
|
|
1560
1420
|
if (options.clearCache) {
|
|
@@ -1578,58 +1438,33 @@ function getPackageVersion() {
|
|
|
1578
1438
|
}
|
|
1579
1439
|
}
|
|
1580
1440
|
var VERSION = getPackageVersion();
|
|
1581
|
-
var robotGradient = gradient(["#36d1dc", "#5b86e5"]);
|
|
1582
1441
|
function showWelcome() {
|
|
1583
|
-
const bannerLines = [
|
|
1584
|
-
" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557",
|
|
1585
|
-
" \u2551 \u2551",
|
|
1586
|
-
" \u2551 R O B O T C L I \u2551",
|
|
1587
|
-
" \u2551 \u2551",
|
|
1588
|
-
" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"
|
|
1589
|
-
].join("\n");
|
|
1590
|
-
console.log();
|
|
1591
|
-
console.log(robotGradient.multiline(bannerLines));
|
|
1592
1442
|
console.log();
|
|
1593
|
-
console.log(chalk5.
|
|
1594
|
-
console.log(chalk5.
|
|
1443
|
+
console.log(chalk5.cyan(" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
|
|
1444
|
+
console.log(chalk5.cyan(" \u2551") + chalk5.bold.cyan(" R O B O T C L I ") + chalk5.cyan("\u2551"));
|
|
1445
|
+
console.log(chalk5.cyan(" \u2551") + chalk5.dim(` v${VERSION} | \u5DE5\u7A0B\u5316\u9879\u76EE\u811A\u624B\u67B6`.padEnd(38)) + chalk5.cyan("\u2551"));
|
|
1446
|
+
console.log(chalk5.cyan(" \u2551") + chalk5.dim(" \u524D\u7AEF / \u540E\u7AEF / \u79FB\u52A8\u7AEF / \u684C\u9762\u7AEF".padEnd(38)) + chalk5.cyan("\u2551"));
|
|
1447
|
+
console.log(chalk5.cyan(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
|
|
1595
1448
|
console.log();
|
|
1596
1449
|
}
|
|
1597
1450
|
async function showMainMenu() {
|
|
1598
1451
|
const allTemplates = getAllTemplates();
|
|
1599
1452
|
const count = Object.keys(allTemplates).length;
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
},
|
|
1616
|
-
{
|
|
1617
|
-
name: `${chalk5.cyan(">")} ${chalk5.bold("\u67E5\u770B\u6A21\u677F\u5217\u8868")} ${chalk5.dim("\u2014 \u6D4F\u89C8\u6240\u6709\u53EF\u7528\u6A21\u677F")}`,
|
|
1618
|
-
value: "list"
|
|
1619
|
-
},
|
|
1620
|
-
{
|
|
1621
|
-
name: `${chalk5.cyan(">")} ${chalk5.bold("\u641C\u7D22\u6A21\u677F")} ${chalk5.dim("\u2014 \u6309\u5173\u952E\u8BCD\u641C\u7D22\u6A21\u677F")}`,
|
|
1622
|
-
value: "search"
|
|
1623
|
-
},
|
|
1624
|
-
{
|
|
1625
|
-
name: `${chalk5.cyan(">")} ${chalk5.bold("\u73AF\u5883\u8BCA\u65AD")} ${chalk5.dim("\u2014 \u68C0\u67E5\u5F00\u53D1\u73AF\u5883")}`,
|
|
1626
|
-
value: "doctor"
|
|
1627
|
-
},
|
|
1628
|
-
{ name: chalk5.dim("\u2500".repeat(50)), value: "sep", disabled: true },
|
|
1629
|
-
{ name: `${chalk5.dim(" \u9000\u51FA")}`, value: "exit" }
|
|
1630
|
-
]
|
|
1631
|
-
}
|
|
1632
|
-
]);
|
|
1453
|
+
p2.intro(chalk5.bgCyan.black(` ${count} \u4E2A\u6A21\u677F\u53EF\u7528 \xB7 Node ${process.version} \xB7 v${VERSION} `));
|
|
1454
|
+
const action = await p2.select({
|
|
1455
|
+
message: "\u8BF7\u9009\u62E9\u64CD\u4F5C:",
|
|
1456
|
+
options: [
|
|
1457
|
+
{ value: "create", label: "\u521B\u5EFA\u65B0\u9879\u76EE", hint: "\u9009\u62E9\u6A21\u677F\u521B\u5EFA\u9879\u76EE" },
|
|
1458
|
+
{ value: "list", label: "\u67E5\u770B\u6A21\u677F\u5217\u8868", hint: "\u6D4F\u89C8\u6240\u6709\u53EF\u7528\u6A21\u677F" },
|
|
1459
|
+
{ value: "search", label: "\u641C\u7D22\u6A21\u677F", hint: "\u6309\u5173\u952E\u8BCD\u641C\u7D22\u6A21\u677F" },
|
|
1460
|
+
{ value: "doctor", label: "\u73AF\u5883\u8BCA\u65AD", hint: "\u68C0\u67E5\u5F00\u53D1\u73AF\u5883" },
|
|
1461
|
+
{ value: "exit", label: "\u9000\u51FA" }
|
|
1462
|
+
]
|
|
1463
|
+
});
|
|
1464
|
+
if (p2.isCancel(action)) {
|
|
1465
|
+
p2.outro(chalk5.dim("\u518D\u89C1!"));
|
|
1466
|
+
process.exit(0);
|
|
1467
|
+
}
|
|
1633
1468
|
switch (action) {
|
|
1634
1469
|
case "create":
|
|
1635
1470
|
await createProject(void 0, {});
|
|
@@ -1644,7 +1479,7 @@ async function showMainMenu() {
|
|
|
1644
1479
|
await runDoctor();
|
|
1645
1480
|
break;
|
|
1646
1481
|
case "exit":
|
|
1647
|
-
|
|
1482
|
+
p2.outro(chalk5.dim("\u518D\u89C1!"));
|
|
1648
1483
|
process.exit(0);
|
|
1649
1484
|
}
|
|
1650
1485
|
}
|
|
@@ -1668,14 +1503,11 @@ function showTemplateList(recommended) {
|
|
|
1668
1503
|
}
|
|
1669
1504
|
}
|
|
1670
1505
|
async function searchInteractive() {
|
|
1671
|
-
const
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
validate: (i) => i.trim() ? true : "\u8BF7\u8F93\u5165\u5173\u952E\u8BCD"
|
|
1677
|
-
}
|
|
1678
|
-
]);
|
|
1506
|
+
const keyword = await p2.text({
|
|
1507
|
+
message: "\u641C\u7D22\u5173\u952E\u8BCD:",
|
|
1508
|
+
validate: (i) => i?.trim() ? void 0 : "\u8BF7\u8F93\u5165\u5173\u952E\u8BCD"
|
|
1509
|
+
});
|
|
1510
|
+
if (p2.isCancel(keyword)) return;
|
|
1679
1511
|
showSearchResults(keyword);
|
|
1680
1512
|
}
|
|
1681
1513
|
function showSearchResults(keyword) {
|