create-qs 0.0.0 → 0.8.21

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 (59) hide show
  1. package/README.md +48 -2
  2. package/README.zh-CN.md +36 -0
  3. package/README.zh-TW.md +36 -0
  4. package/index.js +1883 -0
  5. package/package.json +33 -5
  6. package/template/default/.quicksilver/.gitattributes +4 -0
  7. package/template/default/.quicksilver/manual/en-US/00-setup.md +197 -0
  8. package/template/default/.quicksilver/manual/zh-CN/00-setup.md +197 -0
  9. package/template/default/.quicksilver/manual/zh-TW/00-setup.md +197 -0
  10. package/template/default/AGENTS.md +322 -0
  11. package/template/default/README.md +5 -0
  12. package/template/default/_gitignore +70 -0
  13. package/template/default/build.gradle.kts +5 -0
  14. package/template/default/eslint.config.js +137 -0
  15. package/template/default/gradle/repo.settings.gradle.kts +90 -0
  16. package/template/default/gradle/wrapper/gradle-wrapper.jar +0 -0
  17. package/template/default/gradle/wrapper/gradle-wrapper.properties +7 -0
  18. package/template/default/gradle.properties +15 -0
  19. package/template/default/gradlew +248 -0
  20. package/template/default/gradlew.bat +93 -0
  21. package/template/default/modules/{{MODULE_DIRECTORY}}/api/build.gradle.kts +8 -0
  22. package/template/default/modules/{{MODULE_DIRECTORY}}/api/src/main/kotlin/{{API_PACKAGE}}/AutoConfiguration.kt +25 -0
  23. package/template/default/modules/{{MODULE_DIRECTORY}}/api/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +1 -0
  24. package/template/default/modules/{{MODULE_DIRECTORY}}/api/src/main/resources/QUICKSILVER-INF/data/init.jsons +2 -0
  25. package/template/default/modules/{{MODULE_DIRECTORY}}/api/src/test/kotlin/{{API_PACKAGE}}/SmokeTests.kt +58 -0
  26. package/template/default/modules/{{MODULE_DIRECTORY}}/api/src/test/kotlin/{{API_PACKAGE}}/TestConfiguration.kt +6 -0
  27. package/template/default/modules/{{MODULE_DIRECTORY}}/module.yaml +8 -0
  28. package/template/default/modules/{{MODULE_DIRECTORY}}/web/package.json +25 -0
  29. package/template/default/modules/{{MODULE_DIRECTORY}}/web/src/module.ts +16 -0
  30. package/template/default/modules/{{MODULE_DIRECTORY}}/web/src/vite-env.d.ts +10 -0
  31. package/template/default/modules/{{MODULE_DIRECTORY}}/web/tsconfig.app.json +7 -0
  32. package/template/default/modules/{{MODULE_DIRECTORY}}/web/tsconfig.json +7 -0
  33. package/template/default/modules/{{MODULE_DIRECTORY}}/web/tsconfig.node.json +7 -0
  34. package/template/default/modules/{{MODULE_DIRECTORY}}/web/vite.config.ts +11 -0
  35. package/template/default/package.json +76 -0
  36. package/template/default/pnpm-workspace.yaml +35 -0
  37. package/template/default/publishing.yaml +49 -0
  38. package/template/default/quicksilver.yaml +13 -0
  39. package/template/default/run/api/build.gradle.kts +8 -0
  40. package/template/default/run/api/config/README.md +67 -0
  41. package/template/default/run/api/config/application-dev.yaml +25 -0
  42. package/template/default/run/api/config/application-h2.yaml +22 -0
  43. package/template/default/run/api/config/application-mariadb.yaml +22 -0
  44. package/template/default/run/api/config/application-mssql.yaml +22 -0
  45. package/template/default/run/api/config/application-oracle.yaml +22 -0
  46. package/template/default/run/api/config/application-postgresql.yaml +22 -0
  47. package/template/default/run/api/config/application-test.yaml +28 -0
  48. package/template/default/run/api/config/application.yaml +84 -0
  49. package/template/default/run/api/config/logback-test.xml +141 -0
  50. package/template/default/run/api/config/logback.xml +142 -0
  51. package/template/default/run/web/index.html +14 -0
  52. package/template/default/run/web/index.ts +6 -0
  53. package/template/default/run/web/package.json +18 -0
  54. package/template/default/run/web/static/config.js +15 -0
  55. package/template/default/run/web/tsconfig.app.json +4 -0
  56. package/template/default/run/web/tsconfig.json +7 -0
  57. package/template/default/run/web/tsconfig.node.json +4 -0
  58. package/template/default/run/web/vite.config.ts +21 -0
  59. package/template/default/settings.gradle.kts +19 -0
package/index.js ADDED
@@ -0,0 +1,1883 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import chalk4, { chalkStderr } from 'chalk';
4
+ import * as fs3 from 'fs';
5
+ import fs3__default from 'fs';
6
+ import * as path5 from 'path';
7
+ import path5__default from 'path';
8
+ import { fileURLToPath } from 'url';
9
+ import fs6 from 'fs-extra';
10
+ import readline from 'readline';
11
+ import enquirer from 'enquirer';
12
+ import os from 'os';
13
+ import { randomUUID } from 'crypto';
14
+
15
+ // src/utils/constants.ts
16
+ var UsageError = class extends Error {
17
+ constructor(message) {
18
+ super(message);
19
+ this.name = "UsageError";
20
+ }
21
+ };
22
+
23
+ // ../shared/commons/src/utils/jsons.ts
24
+ function literal(value) {
25
+ if (typeof value === "string") {
26
+ return quoteString(value);
27
+ }
28
+ if (typeof value === "number" || typeof value === "boolean" || value === null) {
29
+ return String(value);
30
+ }
31
+ if (value === void 0) {
32
+ return "null";
33
+ }
34
+ return JSON.stringify(value);
35
+ }
36
+ function quoteString(value) {
37
+ const escaped = value.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t").replace(new RegExp("\\p{Cc}", "gu"), (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`);
38
+ return `'${escaped}'`;
39
+ }
40
+
41
+ // ../shared/commons/src/utils/map-utils.ts
42
+ var MapUtils = class {
43
+ static getOrPut(map, key, create) {
44
+ if (map.has(key)) {
45
+ return map.get(key);
46
+ }
47
+ const value = create();
48
+ map.set(key, value);
49
+ return value;
50
+ }
51
+ static fromArray(array, keyGetter, valueGetter) {
52
+ const map = /* @__PURE__ */ new Map();
53
+ for (const item of array) {
54
+ map.set(keyGetter(item), valueGetter ? valueGetter(item) : item);
55
+ }
56
+ return map;
57
+ }
58
+ };
59
+ var Message = class {
60
+ static styles = {
61
+ hint: { icon: "\u2139", color: (text) => text },
62
+ info: { icon: "\u2139", color: chalk4.cyan },
63
+ success: { icon: "\u2714", color: chalk4.green },
64
+ warn: { icon: "\u26A0", color: chalk4.yellow },
65
+ error: { icon: "\u2716", color: chalk4.red }
66
+ };
67
+ static hint(...messages) {
68
+ this.print("hint", false, ...messages);
69
+ }
70
+ static info(...messages) {
71
+ this.print("info", false, ...messages);
72
+ }
73
+ static success(...messages) {
74
+ this.print("success", false, ...messages);
75
+ }
76
+ static warn(...messages) {
77
+ this.print("warn", false, ...messages);
78
+ }
79
+ static error(...messages) {
80
+ this.print("error", false, ...messages);
81
+ }
82
+ static iconHint(...messages) {
83
+ this.print("hint", true, ...messages);
84
+ }
85
+ static iconInfo(...messages) {
86
+ this.print("info", true, ...messages);
87
+ }
88
+ static iconSuccess(...messages) {
89
+ this.print("success", true, ...messages);
90
+ }
91
+ static iconWarn(...messages) {
92
+ this.print("warn", true, ...messages);
93
+ }
94
+ static iconError(...messages) {
95
+ this.print("error", true, ...messages);
96
+ }
97
+ static blankLine() {
98
+ console.log();
99
+ }
100
+ static print(type, withIcon, ...messages) {
101
+ const style = this.styles[type];
102
+ const text = messages.map((it) => this.formatMessage(it)).join(" ");
103
+ console.log(style.color(withIcon ? `${style.icon} ${text}` : text));
104
+ }
105
+ static formatMessage(message) {
106
+ if (message instanceof Error) {
107
+ return message.stack ?? message.message;
108
+ } else if (typeof message === "object" && message !== null) {
109
+ try {
110
+ return JSON.stringify(message, null, 2);
111
+ } catch {
112
+ return String(message);
113
+ }
114
+ } else {
115
+ return String(message);
116
+ }
117
+ }
118
+ };
119
+
120
+ // ../shared/commons/src/i18n/language.ts
121
+ var LOCALE_VARIABLES = ["LANGUAGE", "LC_ALL", "LC_MESSAGES", "LANG"];
122
+ var POSIX_VARIABLES = ["LC_ALL", "LC_MESSAGES", "LANG"];
123
+ var TRADITIONAL_REGIONS = /* @__PURE__ */ new Set(["TW", "HK", "MO"]);
124
+ function resolveLanguage(env = process.env) {
125
+ for (const name of LOCALE_VARIABLES) {
126
+ const value = env[name]?.trim();
127
+ if (!value) {
128
+ continue;
129
+ }
130
+ if (name === "LANGUAGE" && isPosixLocale(env)) {
131
+ continue;
132
+ }
133
+ return parseLocale(value) ?? "en-US";
134
+ }
135
+ return parseLocale(safeRuntimeLocale()) ?? "en-US";
136
+ }
137
+ function isPosixLocale(env) {
138
+ for (const name of POSIX_VARIABLES) {
139
+ const value = env[name]?.trim();
140
+ if (value) {
141
+ const tag = value.split(/[.@]/)[0];
142
+ return tag === "C" || tag === "POSIX";
143
+ }
144
+ }
145
+ return false;
146
+ }
147
+ function parseLocale(value) {
148
+ if (!value) {
149
+ return void 0;
150
+ }
151
+ const tag = value.split(/[.@:]/)[0].replace(/_/g, "-");
152
+ const parts = tag.split("-").filter(Boolean);
153
+ if (parts[0]?.toLowerCase() !== "zh") {
154
+ return void 0;
155
+ }
156
+ for (const part of parts.slice(1)) {
157
+ const upper = part.toUpperCase();
158
+ if (upper === "HANT" || TRADITIONAL_REGIONS.has(upper)) {
159
+ return "zh-TW";
160
+ }
161
+ if (upper === "HANS") {
162
+ return "zh-CN";
163
+ }
164
+ }
165
+ return "zh-CN";
166
+ }
167
+ function safeRuntimeLocale() {
168
+ try {
169
+ return Intl.DateTimeFormat().resolvedOptions().locale;
170
+ } catch {
171
+ return void 0;
172
+ }
173
+ }
174
+ var MANUAL_DIR = ".quicksilver/manual";
175
+ var MANUAL_SOURCE_LANGUAGE = "zh-CN";
176
+ function manualChapterPath(projectDir, chapter, language2 = resolveLanguage()) {
177
+ const own = `${MANUAL_DIR}/${language2}/${chapter}`;
178
+ if (language2 !== MANUAL_SOURCE_LANGUAGE && fs3__default.existsSync(path5__default.join(projectDir, own))) {
179
+ return own;
180
+ }
181
+ return `${MANUAL_DIR}/${MANUAL_SOURCE_LANGUAGE}/${chapter}`;
182
+ }
183
+
184
+ // ../shared/commons/src/i18n/catalog.ts
185
+ function createCatalog(texts2, language2 = resolveLanguage()) {
186
+ return {
187
+ language: language2,
188
+ t(key, ...args) {
189
+ return texts2[key][language2].replace(/\{(\d)}/g, (_, index) => String(args[Number(index)] ?? ""));
190
+ }
191
+ };
192
+ }
193
+
194
+ // ../shared/commons/src/text/wrap.ts
195
+ var WIDE = /[\u1100-\u115F\u2E80-\u303E\u3041-\u33FF\u3400-\u4DBF\u4E00-\u9FFF\uA000-\uA4CF\uAC00-\uD7A3\uF900-\uFAFF\uFE30-\uFE4F\uFF00-\uFF60\uFFE0-\uFFE6\u{20000}-\u{3FFFD}\p{Emoji_Presentation}]/u;
196
+ var NO_BREAK_BEFORE = /* @__PURE__ */ new Set([..."\u3002\uFF0C\u3001\uFF1A\uFF1B\uFF01\uFF1F\uFF09\u300D\u300F\u3011\u300B\u3009", ...",.;:!?)]"]);
197
+ var NO_BREAK_AFTER = /* @__PURE__ */ new Set([..."\uFF08\u300C\u300E\u3010\u300A\u3008", ..."(["]);
198
+ var WARNING_MARK = "\u26A0";
199
+ var GRAPHEMES = new Intl.Segmenter(void 0, { granularity: "grapheme" });
200
+ function graphemes(text) {
201
+ return Array.from(GRAPHEMES.segment(text), (it) => it.segment);
202
+ }
203
+ function isWide(ch) {
204
+ return WIDE.test(ch) || /[️⃣]/u.test(ch);
205
+ }
206
+ function charWidth(ch) {
207
+ return isWide(ch) ? 2 : 1;
208
+ }
209
+ function textWidth(text) {
210
+ return graphemes(text.replace(/`/g, "")).reduce((n, ch) => n + charWidth(ch), 0);
211
+ }
212
+ function tokenize(text) {
213
+ const raw = [];
214
+ for (const part of text.match(/`[^`]*`|\s+|[^\s`]+|`/gu) ?? []) {
215
+ if (part.startsWith("`") || /^\s/.test(part)) {
216
+ raw.push(part);
217
+ continue;
218
+ }
219
+ let word = "";
220
+ for (const ch of graphemes(part)) {
221
+ if (!isWide(ch)) {
222
+ if (!word && NO_BREAK_BEFORE.has(ch)) {
223
+ raw.push(ch);
224
+ continue;
225
+ }
226
+ word += ch;
227
+ continue;
228
+ }
229
+ if (word) {
230
+ raw.push(word);
231
+ word = "";
232
+ }
233
+ raw.push(ch);
234
+ }
235
+ if (word) {
236
+ raw.push(word);
237
+ }
238
+ }
239
+ const tokens = [];
240
+ let opening = "";
241
+ for (let index = 0; index < raw.length; index++) {
242
+ const token = raw[index];
243
+ if (token === WARNING_MARK && /^\s+$/.test(raw[index + 1] ?? "")) {
244
+ opening += WARNING_MARK + " ";
245
+ index++;
246
+ } else if (/^\s+$/.test(token)) {
247
+ if (opening) {
248
+ tokens.push(opening);
249
+ opening = "";
250
+ }
251
+ tokens.push(" ");
252
+ } else if (NO_BREAK_AFTER.has(token)) {
253
+ opening += token;
254
+ } else if (!opening && NO_BREAK_BEFORE.has(token) && tokens.length > 0 && tokens[tokens.length - 1] !== " ") {
255
+ tokens[tokens.length - 1] += token;
256
+ } else {
257
+ tokens.push(opening + token);
258
+ opening = "";
259
+ }
260
+ }
261
+ if (opening) {
262
+ tokens.push(opening);
263
+ }
264
+ return tokens;
265
+ }
266
+ function wrap(text, width) {
267
+ const greedy = fill(text, width);
268
+ if (greedy.length < 2) {
269
+ return greedy;
270
+ }
271
+ let balanced = greedy;
272
+ for (let narrower = width - 1; narrower >= Math.ceil(width / 2); narrower--) {
273
+ const candidate = fill(text, narrower);
274
+ if (candidate.length > greedy.length) {
275
+ break;
276
+ }
277
+ balanced = candidate;
278
+ }
279
+ return balanced;
280
+ }
281
+ function fill(text, width) {
282
+ const lines = [];
283
+ let line = "";
284
+ let lineWidth = 0;
285
+ for (const token of tokenize(text)) {
286
+ if (token === " ") {
287
+ if (line) {
288
+ line += token;
289
+ lineWidth += 1;
290
+ }
291
+ continue;
292
+ }
293
+ const tokenWidth = textWidth(token);
294
+ if (lineWidth + tokenWidth > width && line) {
295
+ lines.push(line.trimEnd());
296
+ line = "";
297
+ lineWidth = 0;
298
+ }
299
+ line += token;
300
+ lineWidth += tokenWidth;
301
+ }
302
+ if (line.trim()) {
303
+ lines.push(line.trimEnd());
304
+ }
305
+ return lines;
306
+ }
307
+
308
+ // ../shared/commons/src/text/naming.ts
309
+ function checkLength(value, { min, max }) {
310
+ if (value.trim().length === 0) {
311
+ return { violation: "empty" };
312
+ }
313
+ if (min !== void 0 && value.length < min) {
314
+ return { violation: "tooShort", limit: min };
315
+ }
316
+ if (max !== void 0 && value.length > max) {
317
+ return { violation: "tooLong", limit: max };
318
+ }
319
+ return void 0;
320
+ }
321
+ function checkSegment(segment, separator) {
322
+ const allowed = separator ? new RegExp(`^[a-z0-9${separator}]+$`) : /^[a-z0-9]+$/;
323
+ if (!allowed.test(segment)) {
324
+ return { violation: "charset" };
325
+ }
326
+ if (!/^[a-z]/.test(segment)) {
327
+ return { violation: "leadingLetter" };
328
+ }
329
+ if (separator && segment.endsWith(separator)) {
330
+ return { violation: "trailingSeparator" };
331
+ }
332
+ if (separator && segment.includes(separator + separator)) {
333
+ return { violation: "doubleSeparator" };
334
+ }
335
+ return void 0;
336
+ }
337
+ function checkKebab(value, rule = {}) {
338
+ return checkLength(value, rule) ?? checkSegment(value, "-");
339
+ }
340
+ function checkAlnum(value, rule = {}) {
341
+ return checkLength(value, rule) ?? checkSegment(value, "");
342
+ }
343
+ function checkSegmented(value, charset, minSegments) {
344
+ if (!charset.test(value)) {
345
+ return { violation: "charset" };
346
+ }
347
+ if (!/^[a-z]/.test(value)) {
348
+ return { violation: "leadingLetter" };
349
+ }
350
+ if (/[._]$/.test(value)) {
351
+ return { violation: "trailingSeparator" };
352
+ }
353
+ if (/[._]{2}/.test(value)) {
354
+ return { violation: "doubleSeparator" };
355
+ }
356
+ if (/\.[^a-z]/.test(value)) {
357
+ return { violation: "segmentLeadingLetter" };
358
+ }
359
+ if (value.split(".").length < minSegments) {
360
+ return { violation: "segments", limit: minSegments };
361
+ }
362
+ return void 0;
363
+ }
364
+ function checkSnakeSegments(value, rule = {}) {
365
+ return checkLength(value, rule) ?? checkSegmented(value, /^[a-z0-9_.]+$/, rule.minSegments ?? 1);
366
+ }
367
+ var JAVA_KEYWORDS = /* @__PURE__ */ new Set([
368
+ "abstract",
369
+ "assert",
370
+ "boolean",
371
+ "break",
372
+ "byte",
373
+ "case",
374
+ "catch",
375
+ "char",
376
+ "class",
377
+ "const",
378
+ "continue",
379
+ "default",
380
+ "do",
381
+ "double",
382
+ "else",
383
+ "enum",
384
+ "extends",
385
+ "final",
386
+ "finally",
387
+ "float",
388
+ "for",
389
+ "goto",
390
+ "if",
391
+ "implements",
392
+ "import",
393
+ "instanceof",
394
+ "int",
395
+ "interface",
396
+ "long",
397
+ "native",
398
+ "new",
399
+ "package",
400
+ "private",
401
+ "protected",
402
+ "public",
403
+ "return",
404
+ "short",
405
+ "static",
406
+ "strictfp",
407
+ "super",
408
+ "switch",
409
+ "synchronized",
410
+ "this",
411
+ "throw",
412
+ "throws",
413
+ "transient",
414
+ "try",
415
+ "void",
416
+ "volatile",
417
+ "while",
418
+ "true",
419
+ "false",
420
+ "null",
421
+ // Kotlin 的硬关键字里 Java 没有的
422
+ "as",
423
+ "fun",
424
+ "in",
425
+ "is",
426
+ "object",
427
+ "typealias",
428
+ "typeof",
429
+ "val",
430
+ "var",
431
+ "when"
432
+ ]);
433
+ function checkJavaPackage(value, rule = {}) {
434
+ const bad = checkLength(value, rule) ?? checkSegmented(value, /^[a-z0-9.]+$/, 2);
435
+ if (bad) {
436
+ return bad;
437
+ }
438
+ return value.split(".").some((segment) => JAVA_KEYWORDS.has(segment)) ? { violation: "keyword" } : void 0;
439
+ }
440
+ function checkNpmPackage(value, rule = {}) {
441
+ const length = checkLength(value, rule);
442
+ if (length) {
443
+ return length;
444
+ }
445
+ const match = /^(?:@([^/]*)\/)?([^/]*)$/.exec(value);
446
+ if (!match) {
447
+ return { violation: "charset" };
448
+ }
449
+ const [, scope, name] = match;
450
+ for (const part of scope === void 0 ? [name] : [scope, name]) {
451
+ if (!/^[a-z0-9-]+$/.test(part)) {
452
+ return { violation: "charset" };
453
+ }
454
+ if (!/^[a-z0-9]/.test(part)) {
455
+ return { violation: "leadingLetter" };
456
+ }
457
+ if (part.endsWith("-")) {
458
+ return { violation: "trailingSeparator" };
459
+ }
460
+ if (part.includes("--")) {
461
+ return { violation: "doubleSeparator" };
462
+ }
463
+ }
464
+ return void 0;
465
+ }
466
+ function checkDisplayName(value, { max }) {
467
+ const trimmed = value.trim();
468
+ if (trimmed.length === 0) {
469
+ return { violation: "empty" };
470
+ }
471
+ if (new RegExp("[\\p{Cc}\\p{Zl}\\p{Zp}]|(?![\\u200C\\u200D])\\p{Cf}", "u").test(trimmed)) {
472
+ return { violation: "controlChars" };
473
+ }
474
+ return trimmed.length > max ? { violation: "tooLong", limit: max } : void 0;
475
+ }
476
+
477
+ // ../shared/commons/src/prompt/prompt-texts.ts
478
+ var TEXTS_BY_LANGUAGE = {
479
+ "en-US": {
480
+ multiselectHelp: "\u2191/\u2193: Move | Space: Toggle | Ctrl+A: Select ALL | Enter: Confirm",
481
+ multiselectRequired: "Please select at least one item",
482
+ multiselectNone: "NONE",
483
+ selectHelp: "\u2191/\u2193: Move | Enter: Confirm",
484
+ confirmHint: "Please press 'y' or 'n'"
485
+ },
486
+ "zh-CN": {
487
+ multiselectHelp: "\u2191/\u2193 \u79FB\u52A8 | \u7A7A\u683C \u9009\u62E9 | Ctrl+A \u5168\u9009 | Enter \u786E\u8BA4",
488
+ multiselectRequired: "\u8BF7\u81F3\u5C11\u9009\u62E9\u4E00\u9879",
489
+ multiselectNone: "\u65E0",
490
+ selectHelp: "\u2191/\u2193 \u79FB\u52A8 | Enter \u786E\u8BA4",
491
+ confirmHint: "\u8BF7\u6309 y \u6216 n"
492
+ },
493
+ "zh-TW": {
494
+ multiselectHelp: "\u2191/\u2193 \u79FB\u52D5 | \u7A7A\u767D\u9375 \u9078\u64C7 | Ctrl+A \u5168\u9078 | Enter \u78BA\u8A8D",
495
+ multiselectRequired: "\u8ACB\u81F3\u5C11\u9078\u64C7\u4E00\u9805",
496
+ multiselectNone: "\u7121",
497
+ selectHelp: "\u2191/\u2193 \u79FB\u52D5 | Enter \u78BA\u8A8D",
498
+ confirmHint: "\u8ACB\u6309 y \u6216 n"
499
+ }
500
+ };
501
+ var DEFAULT_TEXTS = TEXTS_BY_LANGUAGE["en-US"];
502
+ var texts = { ...DEFAULT_TEXTS };
503
+ function setPromptLanguage(language2) {
504
+ texts = { ...TEXTS_BY_LANGUAGE[language2] };
505
+ }
506
+ function promptTexts() {
507
+ return texts;
508
+ }
509
+ var PromptCancelled = class extends Error {
510
+ constructor() {
511
+ super("Cancelled by user");
512
+ this.name = "PromptCancelled";
513
+ }
514
+ };
515
+ function isPromptCancelled(error) {
516
+ return error instanceof Error && error.name === "PromptCancelled";
517
+ }
518
+ function printCancelled(message) {
519
+ Message.blankLine();
520
+ console.log(message);
521
+ Message.blankLine();
522
+ }
523
+ function cancelledLine(message) {
524
+ return chalk4.dim(`\u2716 ${message}`);
525
+ }
526
+
527
+ // ../shared/commons/src/prompt/ansi-escape.ts
528
+ var CSI = "\x1B[";
529
+ function up(n = 1) {
530
+ return `${CSI}${n}A`;
531
+ }
532
+ function upStart(n = 1) {
533
+ return `${CSI}${n}F`;
534
+ }
535
+ function upClear(n = 1) {
536
+ return `${up()}${clearLine()}`.repeat(n);
537
+ }
538
+ function down(n = 1) {
539
+ return `${CSI}${n}B`;
540
+ }
541
+ function downClear(n = 1) {
542
+ return `${down()}${clearLine()}`.repeat(n);
543
+ }
544
+ function column(n = 1) {
545
+ return `${CSI}${n}G`;
546
+ }
547
+ function home() {
548
+ return column(1);
549
+ }
550
+ function clearLine() {
551
+ return `${CSI}2K`;
552
+ }
553
+ function clearLineFromCursor() {
554
+ return `${CSI}0K`;
555
+ }
556
+ function hideCursor() {
557
+ return "\x1B[?25l";
558
+ }
559
+ function showCursor() {
560
+ return "\x1B[?25h";
561
+ }
562
+
563
+ // ../shared/commons/src/prompt/confirm.ts
564
+ var ConfirmPrompt = class {
565
+ rl = readline.createInterface({ input: process.stdin, output: process.stdout });
566
+ message;
567
+ initial;
568
+ inputting = true;
569
+ showHint = false;
570
+ result = void 0;
571
+ renderedState = { showHint: false };
572
+ constructor(options) {
573
+ this.message = options.message;
574
+ this.initial = options.initial;
575
+ readline.emitKeypressEvents(process.stdin, this.rl);
576
+ if (process.stdin.isTTY) {
577
+ process.stdin.setRawMode(true);
578
+ }
579
+ }
580
+ async run() {
581
+ this.render();
582
+ return new Promise((resolve3, reject) => {
583
+ this.showHint = false;
584
+ process.stdout.write(hideCursor());
585
+ process.stdin.on("keypress", (_, key) => {
586
+ if (key.name === "return") {
587
+ process.stdout.write(up());
588
+ if (typeof this.initial === "boolean") {
589
+ resolve3(this.finish(this.initial));
590
+ } else {
591
+ this.showHint = true;
592
+ }
593
+ } else if (["y", "Y", "n", "N"].includes(key.name)) {
594
+ resolve3(this.finish(key.name === "y" || key.name === "Y"));
595
+ } else if (key.ctrl && key.name === "c") {
596
+ this.exit();
597
+ reject(new PromptCancelled());
598
+ } else {
599
+ this.showHint = true;
600
+ }
601
+ this.render();
602
+ });
603
+ });
604
+ }
605
+ render() {
606
+ process.stdout.write(`${home()}${clearLine()}`);
607
+ if (!this.showHint && this.renderedState.showHint) {
608
+ process.stdout.write(downClear(2) + up(2));
609
+ }
610
+ if (this.inputting) {
611
+ const prompt = typeof this.initial === "undefined" ? "(y/n)" : this.initial ? "(Y/n)" : "(y/N)";
612
+ process.stdout.write(chalk4.cyan("? ") + chalk4.bold(this.message) + chalk4.dim(` ${prompt} \u203A `));
613
+ if (this.showHint) {
614
+ process.stdout.write(`
615
+
616
+ ${chalk4.cyan(`\u2139 ${promptTexts().confirmHint}`)}`);
617
+ process.stdout.write(up(2));
618
+ }
619
+ } else if (typeof this.result === "boolean") {
620
+ const resultText = chalk4.green(this.result ? "Y" : "N");
621
+ console.log(chalk4.green("\u2714 ") + chalk4.bold(this.message) + chalk4.dim(" \xB7 ") + resultText);
622
+ } else {
623
+ console.log(cancelledLine(this.message));
624
+ }
625
+ this.renderedState = { showHint: this.showHint };
626
+ }
627
+ finish(result) {
628
+ this.result = result;
629
+ this.exit();
630
+ return result;
631
+ }
632
+ exit() {
633
+ this.inputting = false;
634
+ this.showHint = false;
635
+ this.rl.close();
636
+ if (process.stdin.isTTY) {
637
+ process.stdin.setRawMode(false);
638
+ }
639
+ process.stdin.removeAllListeners("keypress");
640
+ process.stdout.write(showCursor());
641
+ }
642
+ };
643
+ async function inputBoolean(options, initial) {
644
+ const opts = typeof options === "object" ? options : { message: options, initial };
645
+ return new ConfirmPrompt(opts).run();
646
+ }
647
+ var { Input } = enquirer;
648
+ var TextPrompt = class extends Input {
649
+ async close() {
650
+ try {
651
+ await super.close();
652
+ } catch (error) {
653
+ if (error.code !== "ERR_USE_AFTER_CLOSE") {
654
+ throw error;
655
+ }
656
+ if (this.stdin.isTTY) {
657
+ this.stdin.setRawMode(false);
658
+ }
659
+ this.emit("close");
660
+ }
661
+ }
662
+ async render() {
663
+ if (!this.state.cancelled) {
664
+ return super.render();
665
+ }
666
+ const line = cancelledLine(this.options.message);
667
+ this.clear(this.state.size);
668
+ this.write(line);
669
+ this.state.prompt = line;
670
+ }
671
+ };
672
+ async function inputText({ validate, prefill, ...options }) {
673
+ const prompt = new TextPrompt({
674
+ ...options,
675
+ name: "text",
676
+ // 校验可能是异步的(查文件在不在)。校验还没回来就被取消的话,这次提交停在这里:enquirer
677
+ // 拿到结果还会接着画,已经收起来的那一问就被画第二遍。挂起的 Promise 不占事件循环
678
+ validate: async (value) => {
679
+ const result = validate ? await validate(value) : true;
680
+ return prompt.state.cancelled ? new Promise(() => void 0) : result;
681
+ }
682
+ });
683
+ if (prefill) {
684
+ prompt.input = prefill;
685
+ prompt.cursor = prefill.length;
686
+ }
687
+ try {
688
+ return await prompt.run();
689
+ } catch (error) {
690
+ throw error === "" ? new PromptCancelled() : error;
691
+ }
692
+ }
693
+ var MultiselectPrompt = class {
694
+ rl = readline.createInterface({ input: process.stdin, output: process.stdout });
695
+ message;
696
+ items;
697
+ itemMap;
698
+ required;
699
+ cursor = 0;
700
+ dependencyMap = /* @__PURE__ */ new Map();
701
+ // 存储每个选项的依赖关系
702
+ reverseDependencyMap = /* @__PURE__ */ new Map();
703
+ // 存储反向依赖关系
704
+ state = "init";
705
+ showRequiredMessage = false;
706
+ constructor(options) {
707
+ this.message = options.message;
708
+ this.items = options.items.map((c) => ({ ...c, checked: c.checked ?? false }));
709
+ this.itemMap = MapUtils.fromArray(this.items, (item) => item.value);
710
+ this.required = options.required ?? true;
711
+ this.cursor = this.items.findIndex((it) => !it.disabled);
712
+ this.buildDependencyMaps();
713
+ readline.emitKeypressEvents(process.stdin, this.rl);
714
+ if (process.stdin.isTTY) {
715
+ process.stdin.setRawMode(true);
716
+ }
717
+ }
718
+ buildDependencyMaps() {
719
+ const getDependencies = (item, set = /* @__PURE__ */ new Set()) => {
720
+ item.dependencies?.filter((code) => !set.has(code)).forEach((code) => {
721
+ set.add(code);
722
+ const next = this.itemMap.get(code);
723
+ if (next && next.dependencies) {
724
+ getDependencies(next, set);
725
+ }
726
+ });
727
+ return set;
728
+ };
729
+ for (const item of this.items) {
730
+ if (item.dependencies && item.dependencies.length > 0) {
731
+ const allDependencies = getDependencies(item);
732
+ this.dependencyMap.set(item.value, allDependencies);
733
+ }
734
+ }
735
+ this.dependencyMap.forEach((dependencies, code) => {
736
+ dependencies.forEach((depValue) => {
737
+ MapUtils.getOrPut(this.reverseDependencyMap, depValue, () => /* @__PURE__ */ new Set()).add(code);
738
+ });
739
+ });
740
+ }
741
+ async run() {
742
+ process.stdout.write(hideCursor());
743
+ this.render();
744
+ return new Promise((resolve3, reject) => {
745
+ let resolved = false;
746
+ const cleanup = () => {
747
+ process.stdin.removeListener("keypress", handleKeypress);
748
+ process.stdin.removeListener("data", handleData);
749
+ };
750
+ const safeResolve = (value) => {
751
+ if (!resolved) {
752
+ resolved = true;
753
+ cleanup();
754
+ resolve3(value);
755
+ }
756
+ };
757
+ const safeReject = (reason) => {
758
+ if (!resolved) {
759
+ resolved = true;
760
+ cleanup();
761
+ reject(reason);
762
+ }
763
+ };
764
+ const handleKeypress = (_str, key) => {
765
+ if (resolved) {
766
+ return;
767
+ } else if (key.name === "up") {
768
+ this.moveCursor(-1);
769
+ } else if (key.name === "down") {
770
+ this.moveCursor(1);
771
+ } else if (key.name === "space") {
772
+ this.showRequiredMessage = false;
773
+ this.toggle(this.cursor);
774
+ } else if (key.ctrl && key.name === "a") {
775
+ this.showRequiredMessage = false;
776
+ this.toggleAll();
777
+ } else if (key.name === "return") {
778
+ process.stdout.write(up());
779
+ if (this.required && !this.items.some((it) => it.checked)) {
780
+ this.showRequiredMessage = true;
781
+ } else {
782
+ safeResolve(this.finish());
783
+ }
784
+ } else if (key.ctrl && key.name === "c") {
785
+ this.state = "cancelled";
786
+ this.exit();
787
+ safeReject(new PromptCancelled());
788
+ }
789
+ this.render();
790
+ };
791
+ const handleData = (data) => {
792
+ if (resolved) {
793
+ return;
794
+ }
795
+ const str = data.toString();
796
+ if (str === "\n" || str === "\r" || str === "\r\n") {
797
+ process.stdout.write(down());
798
+ if (this.required && !this.items.some((it) => it.checked)) {
799
+ this.showRequiredMessage = true;
800
+ this.render();
801
+ } else {
802
+ safeResolve(this.finish());
803
+ }
804
+ }
805
+ };
806
+ process.stdin.on("keypress", handleKeypress);
807
+ process.stdin.on("data", handleData);
808
+ });
809
+ }
810
+ render() {
811
+ const texts2 = promptTexts();
812
+ const hint = this.required && this.showRequiredMessage ? chalk4.cyan(`\u2139 ${typeof this.required === "string" ? this.required : texts2.multiselectRequired}`) : chalk4.dim(texts2.multiselectHelp);
813
+ if (this.state === "init") {
814
+ this.state = "select";
815
+ console.log(chalk4.cyan("? ") + chalk4.bold(this.message) + chalk4.dim(" \u203A"));
816
+ console.log(" " + hint);
817
+ this.writeItems();
818
+ } else if (this.state === "select") {
819
+ process.stdout.write(upStart(this.items.length + 1));
820
+ console.log(chalk4.cyan("? ") + chalk4.bold(this.message) + chalk4.dim(" \u203A"));
821
+ console.log(" " + hint + clearLineFromCursor());
822
+ this.writeItems();
823
+ } else if (this.state === "cancelled") {
824
+ process.stdout.write(down() + upClear(this.items.length + 2));
825
+ console.log(cancelledLine(this.message));
826
+ } else {
827
+ process.stdout.write(down() + upClear(this.items.length + 2));
828
+ const selectedItems = this.items.filter((it) => it.checked);
829
+ const tail = selectedItems.length ? "" : chalk4.green(` ${texts2.multiselectNone}`);
830
+ console.log(chalk4.green("\u2714 ") + chalk4.bold(this.message) + chalk4.dim(" \xB7") + tail);
831
+ selectedItems.forEach((it) => console.log(chalk4.green(` \u25C9 ${it.name}`)));
832
+ }
833
+ }
834
+ writeItems() {
835
+ this.items.forEach((item, index) => this.writeItem(item, index));
836
+ process.stdout.write(up());
837
+ }
838
+ writeItem(item, index) {
839
+ const check = item.checked ? chalk4.green("\u25C9") : "\u25EF";
840
+ if (index === this.cursor) {
841
+ console.log(` ${chalk4.cyan("\u276F")} ${check} ${item.name}`);
842
+ } else if (item.disabled) {
843
+ console.log(` ${chalk4.dim(item.checked ? "\u25C9" : "\u25EF")} ${item.name}`);
844
+ } else {
845
+ console.log(` ${check} ${item.name}`);
846
+ }
847
+ }
848
+ moveCursor(direction) {
849
+ if (!this.items.some((item) => !item.disabled)) {
850
+ this.cursor = -1;
851
+ return;
852
+ }
853
+ let newCursor = this.cursor;
854
+ const length = this.items.length;
855
+ do {
856
+ newCursor = (newCursor + direction + length) % length;
857
+ } while (this.items[newCursor].disabled && newCursor !== this.cursor);
858
+ this.cursor = newCursor;
859
+ }
860
+ toggle(index) {
861
+ if (index < 0 || index >= this.items.length) {
862
+ return;
863
+ }
864
+ const current = this.items[index];
865
+ current.checked = !current.checked;
866
+ const map = current.checked ? this.dependencyMap : this.reverseDependencyMap;
867
+ [...map.get(current.value) ?? []].map((code) => this.itemMap.get(code)).filter((it) => it && !it.disabled && it.checked !== current.checked).forEach((it) => it.checked = current.checked);
868
+ }
869
+ toggleAll() {
870
+ const enabledItems = this.items.filter((item) => !item.disabled);
871
+ if (enabledItems.length === 0) {
872
+ return;
873
+ }
874
+ const allSelected = enabledItems.every((item) => item.checked);
875
+ const newState = !allSelected;
876
+ enabledItems.forEach((item) => {
877
+ item.checked = newState;
878
+ });
879
+ }
880
+ finish() {
881
+ this.state = "finished";
882
+ this.exit();
883
+ return this.items.filter((c) => c.checked).map((c) => c.value);
884
+ }
885
+ exit() {
886
+ this.rl.close();
887
+ if (process.stdin.isTTY) {
888
+ process.stdin.setRawMode(false);
889
+ }
890
+ process.stdin.removeAllListeners("keypress");
891
+ process.stdout.write(showCursor());
892
+ }
893
+ };
894
+ function multiselect(options) {
895
+ return new MultiselectPrompt(options).run();
896
+ }
897
+ var INDENT = " ";
898
+ var MAX_COLUMNS = 100;
899
+ function renderCode(line, color = chalk4.cyan) {
900
+ return line.replace(/`([^`]*)`/g, (_, code) => color(code));
901
+ }
902
+ function printHint(hint, options = {}) {
903
+ const columns = options.columns ?? (process.stdout.columns || 80);
904
+ const width = Math.min(columns, MAX_COLUMNS) - INDENT.length;
905
+ console.log();
906
+ let warned = false;
907
+ for (const line of wrap(hint, width)) {
908
+ const mark = warned ? 0 : line.indexOf(WARNING_MARK);
909
+ if (mark < 0) {
910
+ console.log(INDENT + chalk4.dim(renderCode(line, chalk4.cyan)));
911
+ } else {
912
+ warned = true;
913
+ console.log(INDENT + chalk4.dim(renderCode(line.slice(0, mark), chalk4.cyan)) + chalk4.yellow(renderCode(line.slice(mark), chalk4.yellow)));
914
+ }
915
+ }
916
+ console.log();
917
+ }
918
+ var INDENT2 = " ";
919
+ function renderSummary(title, rows) {
920
+ const labelWidth = Math.max(0, ...rows.map((it) => textWidth(it.label)));
921
+ const lines = [INDENT2 + chalk4.cyan(title)];
922
+ for (const { label, value } of rows) {
923
+ const padding = " ".repeat(labelWidth - textWidth(label) + 2);
924
+ const continuation = " ".repeat(INDENT2.length + labelWidth + 2);
925
+ const [first, ...rest] = value.split("\n");
926
+ lines.push(INDENT2 + chalk4.dim(label) + padding + first);
927
+ for (const line of rest) {
928
+ lines.push(continuation + line);
929
+ }
930
+ }
931
+ return lines;
932
+ }
933
+ function printSummary(title, rows) {
934
+ Message.blankLine();
935
+ for (const line of renderSummary(title, rows)) {
936
+ console.log(line);
937
+ }
938
+ }
939
+ function safeHomedir() {
940
+ try {
941
+ return os.homedir();
942
+ } catch {
943
+ return "";
944
+ }
945
+ }
946
+ function shortenHome(target, home2 = safeHomedir()) {
947
+ if (!home2 || path5__default.parse(home2).root === home2) {
948
+ return target;
949
+ }
950
+ const relative = path5__default.relative(home2, target);
951
+ if (!relative || relative.startsWith("..") || path5__default.isAbsolute(relative)) {
952
+ return target;
953
+ }
954
+ return `~${path5__default.sep}${relative}`;
955
+ }
956
+
957
+ // src/utils/i18n.ts
958
+ var HINTS = {
959
+ projectName: {
960
+ "zh-CN": "\u9879\u76EE\u6839\u76EE\u5F55\u540D\uFF0C\u4F8B\u5982 `power-crm`\u3002\u4E5F\u662F\u4EA7\u54C1\u7F16\u7801\u3001\u6253\u5305\u540D\u4E0E\u5F00\u53D1\u5E93\u540D\u524D\u7F00\uFF08\u90E8\u5206\u573A\u666F\u4E2D\u81EA\u52A8\u5C06\u5B57\u7B26\u8F6C\u4E3A\u4E0B\u5212\u7EBF\uFF09\u3002\u540E\u7EED\u5404\u9879\u7684\u9ED8\u8BA4\u503C\u5747\u7531\u5B83\u63A8\u5BFC\u3002",
961
+ "zh-TW": "\u5C08\u6848\u6839\u76EE\u9304\u540D\uFF0C\u4F8B\u5982 `power-crm`\u3002\u4E5F\u662F\u7522\u54C1\u7DE8\u78BC\u3001\u6253\u5305\u540D\u8207\u958B\u767C\u5EAB\u540D\u524D\u7DB4\uFF08\u90E8\u5206\u5834\u666F\u4E2D\u81EA\u52D5\u5C07\u5B57\u5143\u8F49\u70BA\u5E95\u7DDA\uFF09\u3002\u5F8C\u7E8C\u5404\u9805\u7684\u9810\u8A2D\u503C\u5747\u7531\u5B83\u63A8\u5C0E\u3002",
962
+ "en-US": "The project root directory, e.g. `power-crm`. Also the product code, archive name and dev database prefix (hyphens become underscores where needed). Later defaults are derived from it."
963
+ },
964
+ moduleDirectory: {
965
+ "zh-CN": "`modules` \u76EE\u5F55\u4E0B\u7684\u4E1A\u52A1\u6A21\u5757\u540D\uFF0C\u4F8B\u5982 `sales`\u3002\u4EC5\u5F71\u54CD\u76EE\u5F55\u7ED3\u6784\uFF0C\u540E\u7EED\u8C03\u6574\u7684\u6210\u672C\u8F83\u4F4E\u3002",
966
+ "zh-TW": "`modules` \u76EE\u9304\u4E0B\u7684\u696D\u52D9\u6A21\u7D44\u540D\uFF0C\u4F8B\u5982 `sales`\u3002\u50C5\u5F71\u97FF\u76EE\u9304\u7D50\u69CB\uFF0C\u5F8C\u7E8C\u8ABF\u6574\u7684\u6210\u672C\u8F03\u4F4E\u3002",
967
+ "en-US": "The business module name under `modules`, e.g. `sales`. It affects layout only and is cheap to change later."
968
+ },
969
+ moduleCode: {
970
+ "zh-CN": "\u6A21\u5757\u7684\u5168\u5C40\u552F\u4E00\u4EE3\u7801\uFF0C\u81F3\u5C11\u4E24\u6BB5\uFF0C\u7528 `.` \u5206\u9694\uFF0C\u4F8B\u5982 `power_crm.sales`\u3002\u26A0 \u5347\u7EA7\u811A\u672C\u4F9D\u636E\u5B83\u8BC6\u522B\u6A21\u5757\uFF0C\u53D8\u66F4\u4E4B\u540E\u5C06\u88AB\u89C6\u4E3A\u53E6\u4E00\u4E2A\u6A21\u5757\u3002",
971
+ "zh-TW": "\u6A21\u7D44\u7684\u5168\u57DF\u552F\u4E00\u4EE3\u78BC\uFF0C\u81F3\u5C11\u5169\u6BB5\uFF0C\u7528 `.` \u5206\u9694\uFF0C\u4F8B\u5982 `power_crm.sales`\u3002\u26A0 \u5347\u7D1A\u8173\u672C\u4F9D\u64DA\u5B83\u8B58\u5225\u6A21\u7D44\uFF0C\u8B8A\u66F4\u4E4B\u5F8C\u5C07\u88AB\u8996\u70BA\u53E6\u4E00\u500B\u6A21\u7D44\u3002",
972
+ "en-US": "The globally unique module code, two or more parts joined by `.`, e.g. `power_crm.sales`. \u26A0 Upgrade scripts find the module by it. A new code means a new module."
973
+ },
974
+ moduleNamespace: {
975
+ "zh-CN": "\u5355\u5143\u4E0E\u8868\u540D\u7684\u524D\u7F00\uFF0C\u9ED8\u8BA4\u53D6\u6A21\u5757\u4EE3\u7801\u4E2D\u5404\u5355\u8BCD\u7684\u9996\u5B57\u6BCD\uFF0C\u4F8B\u5982 `power_crm.sales` \u5F97\u5230 `pcs`\u3002\u6A21\u5757\u4E2D\u6BCF\u4E2A\u5355\u5143\u7684 code \u5747\u4EE5\u5B83\u5F00\u5934\u3002",
976
+ "zh-TW": "\u55AE\u5143\u8207\u8CC7\u6599\u8868\u540D\u7A31\u7684\u524D\u7DB4\uFF0C\u9810\u8A2D\u53D6\u6A21\u7D44\u4EE3\u78BC\u4E2D\u5404\u55AE\u5B57\u7684\u9996\u5B57\u6BCD\uFF0C\u4F8B\u5982 `power_crm.sales` \u5F97\u5230 `pcs`\u3002\u6A21\u7D44\u4E2D\u6BCF\u500B\u55AE\u5143\u7684 code \u5747\u4EE5\u5B83\u958B\u982D\u3002",
977
+ "en-US": "Prefix for unit codes and table names. Defaults to the initials of the words in the module code, e.g. `pcs` for `power_crm.sales`. Every unit code in the module starts with it."
978
+ },
979
+ apiPackage: {
980
+ "zh-CN": "Kotlin \u5305\u540D\uFF0C\u4F8B\u5982 `com.company.powercrm`\uFF0C\u6240\u6709\u540E\u7AEF\u7C7B\u90FD\u76F4\u63A5\u6216\u95F4\u63A5\u653E\u5728\u8BE5\u5305\u5185\u3002\u26A0 \u540E\u7EED\u53D8\u66F4\u9700\u8981\u5BF9\u6574\u4E2A\u6A21\u5757\u8FDB\u884C\u91CD\u6784\u3002",
981
+ "zh-TW": "Kotlin \u5957\u4EF6\u540D\u7A31\uFF0C\u4F8B\u5982 `com.company.powercrm`\uFF0C\u6240\u6709\u5F8C\u7AEF\u985E\u5225\u90FD\u76F4\u63A5\u6216\u9593\u63A5\u653E\u5728\u8A72\u5957\u4EF6\u5167\u3002\u26A0 \u5F8C\u7E8C\u8B8A\u66F4\u9700\u8981\u5C0D\u6574\u500B\u6A21\u7D44\u9032\u884C\u91CD\u69CB\u3002",
982
+ "en-US": "The Kotlin package, e.g. `com.company.powercrm`. Every backend class lives in it or below it. \u26A0 Changing it later requires a module-wide refactor."
983
+ },
984
+ apiArtifactId: {
985
+ "zh-CN": "\u540E\u7AEF\u53D1\u5E03\u5230 Maven \u65F6\u7684 artifactId\uFF0C\u4F8B\u5982 `power-crm-module-sales`\u3002\u4EC5\u5728\u53D1\u5E03\u7248\u672C\u65F6\u751F\u6548\uFF0C\u6682\u4E0D\u53D1\u5E03\u53EF\u4FDD\u7559\u9ED8\u8BA4\u503C\u3002",
986
+ "zh-TW": "\u5F8C\u7AEF\u767C\u5E03\u5230 Maven \u6642\u7684 artifactId\uFF0C\u4F8B\u5982 `power-crm-module-sales`\u3002\u50C5\u5728\u767C\u5E03\u7248\u672C\u6642\u751F\u6548\uFF0C\u66AB\u4E0D\u767C\u5E03\u53EF\u4FDD\u7559\u9810\u8A2D\u503C\u3002",
987
+ "en-US": "The artifactId of the backend when published to Maven, e.g. `power-crm-module-sales`. It only takes effect on publish. The default is adequate until then."
988
+ },
989
+ webModulePackage: {
990
+ "zh-CN": "\u524D\u7AEF\u5728 `package.json` \u4E2D\u7684\u5305\u540D\uFF0C\u4F8B\u5982 `@powercrm/module-sales-web`\u3002\u7528\u4E8E\u53D1\u5E03\u7248\u672C\u4E0E\u6A21\u5757\u4E4B\u95F4\u7684\u76F8\u4E92\u5F15\u7528\uFF0C\u5EFA\u8BAE\u5E26\u7EC4\u7EC7\u524D\u7F00\uFF0C\u4FBF\u4E8E\u591A\u6A21\u5757\u5F00\u53D1\u3002",
991
+ "zh-TW": "\u524D\u7AEF\u5728 `package.json` \u4E2D\u7684\u5957\u4EF6\u540D\uFF0C\u4F8B\u5982 `@powercrm/module-sales-web`\u3002\u7528\u65BC\u767C\u5E03\u7248\u672C\u8207\u6A21\u7D44\u4E4B\u9593\u7684\u76F8\u4E92\u5F15\u7528\uFF0C\u5EFA\u8B70\u5E36\u7D44\u7E54\u524D\u7DB4\uFF0C\u4FBF\u65BC\u591A\u6A21\u7D44\u958B\u767C\u3002",
992
+ "en-US": "The web package name in `package.json`, e.g. `@powercrm/module-sales-web`. Used when publishing and when modules import each other. A scoped name is recommended for multi-module work."
993
+ },
994
+ // 不说「平台」:将来可能有产品基于下游产品,这里列出的不一定是平台的模块。
995
+ // 各模块是什么,选项自己那一行的描述已经说了,说明里不重复
996
+ platformModules: {
997
+ "zh-CN": "\u672C\u4EA7\u54C1\u4F9D\u8D56\u7684\u6A21\u5757\uFF0C\u540E\u7EED\u53EF\u518D\u884C\u6DFB\u52A0\u3002",
998
+ "zh-TW": "\u672C\u7522\u54C1\u76F8\u4F9D\u7684\u6A21\u7D44\uFF0C\u5F8C\u7E8C\u53EF\u518D\u884C\u65B0\u589E\u3002",
999
+ "en-US": "Modules this product depends on. More can be added later."
1000
+ },
1001
+ moduleMenu: {
1002
+ "zh-CN": "\u672C\u6A21\u5757\u5728\u5DE6\u4FA7\u5BFC\u822A\u4E2D\u7684\u4E00\u7EA7\u5165\u53E3\uFF0C\u4E0E\u5E73\u53F0\u5185\u7F6E\u7684\u5165\u53E3\u5E76\u5217\u3002\u540E\u7EED\u521B\u5EFA\u7684\u9875\u9762\u53EF\u6302\u8F7D\u4E8E\u5176\u4E0B\uFF0C\u540D\u79F0\u4E0E\u5B58\u5E9F\u5747\u53EF\u968F\u65F6\u8C03\u6574\u3002",
1003
+ "zh-TW": "\u672C\u6A21\u7D44\u5728\u5DE6\u5074\u5C0E\u89BD\u5217\u4E2D\u7684\u4E00\u7D1A\u5165\u53E3\uFF0C\u8207\u5E73\u53F0\u5167\u5EFA\u7684\u5165\u53E3\u4E26\u5217\u3002\u5F8C\u7E8C\u5EFA\u7ACB\u7684\u9801\u9762\u53EF\u639B\u8F09\u65BC\u5176\u4E0B\uFF0C\u540D\u7A31\u8207\u5B58\u5EE2\u5747\u53EF\u96A8\u6642\u8ABF\u6574\u3002",
1004
+ "en-US": "This module's top-level entry in the left nav, alongside the built-in ones. Later pages can be placed under it, and it can be renamed or removed at any time."
1005
+ }
1006
+ };
1007
+ var TEXTS = {
1008
+ banner: {
1009
+ "zh-CN": "\u{1F680} \u6B63\u5728\u521B\u5EFA Quicksilver \u9879\u76EE\u2026",
1010
+ "zh-TW": "\u{1F680} \u6B63\u5728\u5EFA\u7ACB Quicksilver \u5C08\u6848\u2026",
1011
+ "en-US": "\u{1F680} Creating a new Quicksilver project..."
1012
+ },
1013
+ cancelled: {
1014
+ "zh-CN": "\u5DF2\u53D6\u6D88\u3002",
1015
+ "zh-TW": "\u5DF2\u53D6\u6D88\u3002",
1016
+ "en-US": "Cancelled by user."
1017
+ },
1018
+ // 九个问句。它们同时对应一个命令行开关,开关名始终是英文,见文件头。
1019
+ "label.projectName": { "zh-CN": "\u9879\u76EE\u540D\u79F0", "zh-TW": "\u5C08\u6848\u540D\u7A31", "en-US": "Project name" },
1020
+ "label.moduleDirectory": { "zh-CN": "\u6A21\u5757\u76EE\u5F55\u540D", "zh-TW": "\u6A21\u7D44\u76EE\u9304\u540D\u7A31", "en-US": "Module directory name" },
1021
+ "label.moduleCode": { "zh-CN": "\u6A21\u5757\u4EE3\u7801", "zh-TW": "\u6A21\u7D44\u4EE3\u78BC", "en-US": "Module code" },
1022
+ "label.moduleNamespace": { "zh-CN": "\u6A21\u5757\u547D\u540D\u7A7A\u95F4", "zh-TW": "\u6A21\u7D44\u547D\u540D\u7A7A\u9593", "en-US": "Module namespace" },
1023
+ "label.apiPackage": { "zh-CN": "API \u5305\u540D", "zh-TW": "API \u5957\u4EF6\u540D\u7A31", "en-US": "API package name" },
1024
+ "label.apiArtifactId": { "zh-CN": "API \u6784\u4EF6 ID", "zh-TW": "API \u69CB\u4EF6 ID", "en-US": "API artifact ID" },
1025
+ "label.webModulePackage": {
1026
+ "zh-CN": "Web \u6A21\u5757\u5305\u540D",
1027
+ "zh-TW": "Web \u6A21\u7D44\u5957\u4EF6\u540D\u7A31",
1028
+ "en-US": "Web module package name"
1029
+ },
1030
+ "label.platformModules": { "zh-CN": "\u4F9D\u8D56\u54EA\u4E9B\u6A21\u5757", "zh-TW": "\u8981\u76F8\u4F9D\u54EA\u4E9B\u6A21\u7D44", "en-US": "Modules to depend on" },
1031
+ "label.moduleMenu": {
1032
+ "zh-CN": "\u4E3A\u672C\u6A21\u5757\u521B\u5EFA\u9876\u5C42\u83DC\u5355",
1033
+ "zh-TW": "\u70BA\u672C\u6A21\u7D44\u5EFA\u7ACB\u9802\u5C64\u9078\u55AE",
1034
+ "en-US": "Create a top-level menu for this module"
1035
+ },
1036
+ "label.moduleMenuName": { "zh-CN": "\u9876\u5C42\u83DC\u5355\u540D\u79F0", "zh-TW": "\u9802\u5C64\u9078\u55AE\u540D\u7A31", "en-US": "Top-level menu name" },
1037
+ // 校验
1038
+ "validate.empty": { "zh-CN": "{0}\u4E0D\u80FD\u4E3A\u7A7A", "zh-TW": "{0}\u4E0D\u80FD\u70BA\u7A7A", "en-US": "{0} must be a non-empty string" },
1039
+ "validate.badDefault": {
1040
+ "zh-CN": "\u63A8\u5BFC\u51FA\u7684\u9ED8\u8BA4\u503C\u300C{1}\u300D\u4E0D\u53EF\u7528\uFF1A{0}\u3002\u4F7F\u7528 --yes \u65F6\u987B\u901A\u8FC7 {2} \u6307\u5B9A",
1041
+ "zh-TW": "\u63A8\u5C0E\u51FA\u7684\u9810\u8A2D\u503C\u300C{1}\u300D\u4E0D\u53EF\u7528\uFF1A{0}\u3002\u4F7F\u7528 --yes \u6642\u9808\u900F\u904E {2} \u6307\u5B9A",
1042
+ "en-US": 'The derived default "{1}" does not work: {0}. Pass {2} when using --yes'
1043
+ },
1044
+ "validate.controlChars": {
1045
+ "zh-CN": "{0}\u4E0D\u80FD\u5305\u542B\u6362\u884C\u6216\u5176\u5B83\u63A7\u5236\u5B57\u7B26",
1046
+ "zh-TW": "{0}\u4E0D\u80FD\u5305\u542B\u63DB\u884C\u6216\u5176\u5B83\u63A7\u5236\u5B57\u5143",
1047
+ "en-US": "{0} must not contain line breaks or other control characters"
1048
+ },
1049
+ "validate.tooLong": {
1050
+ "zh-CN": "{0}\u4E0D\u80FD\u8D85\u8FC7 {1} \u4E2A\u5B57\u7B26",
1051
+ "zh-TW": "{0}\u4E0D\u80FD\u8D85\u904E {1} \u500B\u5B57\u5143",
1052
+ "en-US": "{0} cannot be longer than {1} characters"
1053
+ },
1054
+ // 命名规范。分隔符与字符集按名字的形态各自一条,其余通用
1055
+ "naming.tooShort": { "zh-CN": "{0}\u81F3\u5C11 {1} \u4F4D", "zh-TW": "{0}\u81F3\u5C11 {1} \u4F4D", "en-US": "{0} must be at least {1} characters" },
1056
+ "naming.leadingLetter": { "zh-CN": "{0}\u5FC5\u987B\u4EE5\u5B57\u6BCD\u5F00\u5934", "zh-TW": "{0}\u5FC5\u9808\u4EE5\u5B57\u6BCD\u958B\u982D", "en-US": "{0} must start with a letter" },
1057
+ "naming.leadingAlnum": {
1058
+ "zh-CN": "{0}\u5FC5\u987B\u4EE5\u5B57\u6BCD\u6216\u6570\u5B57\u5F00\u5934",
1059
+ "zh-TW": "{0}\u5FC5\u9808\u4EE5\u5B57\u6BCD\u6216\u6578\u5B57\u958B\u982D",
1060
+ "en-US": "{0} must start with a letter or digit"
1061
+ },
1062
+ "naming.segmentLeadingLetter": {
1063
+ "zh-CN": "{0}\u7684\u6BCF\u4E00\u6BB5\u90FD\u5FC5\u987B\u4EE5\u5B57\u6BCD\u5F00\u5934",
1064
+ "zh-TW": "{0}\u7684\u6BCF\u4E00\u6BB5\u90FD\u5FC5\u9808\u4EE5\u5B57\u6BCD\u958B\u982D",
1065
+ "en-US": "{0} must start each segment with a letter"
1066
+ },
1067
+ "naming.trailingSeparator": { "zh-CN": "{0}\u4E0D\u80FD\u4EE5{1}\u7ED3\u5C3E", "zh-TW": "{0}\u4E0D\u80FD\u4EE5{1}\u7D50\u5C3E", "en-US": "{0} cannot end with {1}" },
1068
+ "naming.doubleSeparator": {
1069
+ "zh-CN": "{0}\u4E0D\u80FD\u6709\u8FDE\u7EED\u7684{1}",
1070
+ "zh-TW": "{0}\u4E0D\u80FD\u6709\u9023\u7E8C\u7684{1}",
1071
+ "en-US": "{0} cannot contain {1} in a row"
1072
+ },
1073
+ "naming.segments": {
1074
+ "zh-CN": "{0}\u81F3\u5C11\u8981\u6709 {1} \u6BB5\uFF0C\u7528\u70B9\u5206\u9694",
1075
+ "zh-TW": "{0}\u81F3\u5C11\u8981\u6709 {1} \u6BB5\uFF0C\u7528\u9EDE\u5206\u9694",
1076
+ "en-US": "{0} needs at least {1} dot-separated segments"
1077
+ },
1078
+ "naming.keyword": {
1079
+ "zh-CN": "{0}\u7684\u6BB5\u540D\u4E0D\u80FD\u662F Java \u6216 Kotlin \u5173\u952E\u5B57",
1080
+ "zh-TW": "{0}\u7684\u6BB5\u540D\u4E0D\u80FD\u662F Java \u6216 Kotlin \u95DC\u9375\u5B57",
1081
+ "en-US": "{0} cannot use a Java or Kotlin keyword as a segment"
1082
+ },
1083
+ "naming.reservedPrefix": {
1084
+ "zh-CN": "{0}\u4E0D\u80FD\u4EE5 `quicksilver.` \u5F00\u5934\uFF0C\u8FD9\u4E2A\u524D\u7F00\u5F52\u5E73\u53F0\u6A21\u5757",
1085
+ "zh-TW": "{0}\u4E0D\u80FD\u4EE5 `quicksilver.` \u958B\u982D\uFF0C\u9019\u500B\u524D\u7DB4\u6B78\u5E73\u53F0\u6A21\u7D44",
1086
+ "en-US": "{0} cannot start with `quicksilver.`, that prefix belongs to the platform modules"
1087
+ },
1088
+ "naming.platformNamespace": {
1089
+ "zh-CN": "{0}\u4E0D\u80FD\u662F `{1}`\uFF0C\u5E73\u53F0\u6A21\u5757 {2} \u5DF2\u5728\u4F7F\u7528",
1090
+ "zh-TW": "{0}\u4E0D\u80FD\u662F `{1}`\uFF0C\u5E73\u53F0\u6A21\u7D44 {2} \u5DF2\u5728\u4F7F\u7528",
1091
+ "en-US": "{0} cannot be `{1}`, platform module {2} already uses it"
1092
+ },
1093
+ "naming.platformPattern": {
1094
+ "zh-CN": "{0}\u4E0D\u80FD\u662F `{1}`\uFF0C\u5B83\u5C5E\u4E8E\u5E73\u53F0\u4FDD\u7559\u7684 `{2}`",
1095
+ "zh-TW": "{0}\u4E0D\u80FD\u662F `{1}`\uFF0C\u5B83\u5C6C\u65BC\u5E73\u53F0\u4FDD\u7559\u7684 `{2}`",
1096
+ "en-US": "{0} cannot be `{1}`, it falls under `{2}` reserved by the platform"
1097
+ },
1098
+ "naming.charset.kebab": {
1099
+ "zh-CN": "{0}\u53EA\u80FD\u5305\u542B\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u548C\u8FDE\u5B57\u7B26",
1100
+ "zh-TW": "{0}\u53EA\u80FD\u5305\u542B\u5C0F\u5BEB\u5B57\u6BCD\u3001\u6578\u5B57\u8207\u9023\u5B57\u865F",
1101
+ "en-US": "{0} can only contain lowercase letters, digits and hyphens"
1102
+ },
1103
+ "naming.charset.snakeSegments": {
1104
+ "zh-CN": "{0}\u53EA\u80FD\u5305\u542B\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u4E0B\u5212\u7EBF\u548C\u70B9",
1105
+ "zh-TW": "{0}\u53EA\u80FD\u5305\u542B\u5C0F\u5BEB\u5B57\u6BCD\u3001\u6578\u5B57\u3001\u5E95\u7DDA\u8207\u9EDE",
1106
+ "en-US": "{0} can only contain lowercase letters, digits, underscores and dots"
1107
+ },
1108
+ "naming.charset.alnum": {
1109
+ "zh-CN": "{0}\u53EA\u80FD\u5305\u542B\u5C0F\u5199\u5B57\u6BCD\u548C\u6570\u5B57",
1110
+ "zh-TW": "{0}\u53EA\u80FD\u5305\u542B\u5C0F\u5BEB\u5B57\u6BCD\u8207\u6578\u5B57",
1111
+ "en-US": "{0} can only contain lowercase letters and digits"
1112
+ },
1113
+ "naming.charset.javaPackage": {
1114
+ "zh-CN": "{0}\u6BCF\u6BB5\u53EA\u80FD\u5305\u542B\u5C0F\u5199\u5B57\u6BCD\u548C\u6570\u5B57\uFF0C\u6BB5\u4E4B\u95F4\u7528\u70B9\u5206\u9694",
1115
+ "zh-TW": "{0}\u6BCF\u6BB5\u53EA\u80FD\u5305\u542B\u5C0F\u5BEB\u5B57\u6BCD\u8207\u6578\u5B57\uFF0C\u6BB5\u4E4B\u9593\u7528\u9EDE\u5206\u9694",
1116
+ "en-US": "{0} segments can only contain lowercase letters and digits, separated by dots"
1117
+ },
1118
+ "naming.charset.npm": {
1119
+ "zh-CN": "{0}\u53EA\u80FD\u5305\u542B\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u548C\u8FDE\u5B57\u7B26\uFF0C\u53EF\u5E26 @scope/ \u524D\u7F00",
1120
+ "zh-TW": "{0}\u53EA\u80FD\u5305\u542B\u5C0F\u5BEB\u5B57\u6BCD\u3001\u6578\u5B57\u8207\u9023\u5B57\u865F\uFF0C\u53EF\u5E36 @scope/ \u524D\u7DB4",
1121
+ "en-US": "{0} can only contain lowercase letters, digits and hyphens, optionally under a @scope/"
1122
+ },
1123
+ // 分隔符在两条报错里的说法:中文一样,英文一条要冠词、一条要复数
1124
+ "sep.end.hyphen": { "zh-CN": "\u8FDE\u5B57\u7B26", "zh-TW": "\u9023\u5B57\u865F", "en-US": "a hyphen" },
1125
+ "sep.end.dot": { "zh-CN": "\u70B9", "zh-TW": "\u9EDE", "en-US": "a dot" },
1126
+ "sep.end.underscoreOrDot": { "zh-CN": "\u4E0B\u5212\u7EBF\u6216\u70B9", "zh-TW": "\u5E95\u7DDA\u6216\u9EDE", "en-US": "an underscore or a dot" },
1127
+ "sep.pair.hyphen": { "zh-CN": "\u8FDE\u5B57\u7B26", "zh-TW": "\u9023\u5B57\u865F", "en-US": "two hyphens" },
1128
+ "sep.pair.dot": { "zh-CN": "\u70B9", "zh-TW": "\u9EDE", "en-US": "two dots" },
1129
+ "sep.pair.underscoreOrDot": { "zh-CN": "\u4E0B\u5212\u7EBF\u6216\u70B9", "zh-TW": "\u5E95\u7DDA\u6216\u9EDE", "en-US": "two separators (underscore or dot)" },
1130
+ // 平台模块多选
1131
+ // 「必选」由 module.required 那个后缀说,描述里不再说一遍
1132
+ "module.core": { "zh-CN": "\u5E73\u53F0\u6838\u5FC3", "zh-TW": "\u5E73\u53F0\u6838\u5FC3", "en-US": "Platform core" },
1133
+ "module.org": {
1134
+ "zh-CN": "\u7EC4\u7EC7\uFF1A\u90E8\u95E8\u4E0E\u5458\u5DE5",
1135
+ "zh-TW": "\u7D44\u7E54\uFF1A\u90E8\u9580\u8207\u54E1\u5DE5",
1136
+ "en-US": "Organization: departments and employees"
1137
+ },
1138
+ "module.required": { "zh-CN": "\uFF08\u5FC5\u9009\uFF09", "zh-TW": "\uFF08\u5FC5\u9078\uFF09", "en-US": " (Required)" },
1139
+ // 生成
1140
+ // 清单:上面九个问句的标签直接复用,这里只补清单独有的两条
1141
+ "summary.title": {
1142
+ "zh-CN": "\u5C06\u6309\u4EE5\u4E0B\u914D\u7F6E\u521B\u5EFA\u9879\u76EE\uFF1A",
1143
+ "zh-TW": "\u5C07\u6309\u4EE5\u4E0B\u8A2D\u5B9A\u5EFA\u7ACB\u5C08\u6848\uFF1A",
1144
+ "en-US": "The project will be created with:"
1145
+ },
1146
+ "summary.projectPath": { "zh-CN": "\u76EE\u6807\u76EE\u5F55", "zh-TW": "\u76EE\u6A19\u76EE\u9304", "en-US": "Target directory" },
1147
+ "summary.noMenu": { "zh-CN": "\u4E0D\u521B\u5EFA", "zh-TW": "\u4E0D\u5EFA\u7ACB", "en-US": "none" },
1148
+ "summary.projectPathOverwrite": {
1149
+ "zh-CN": "{0}\uFF08\u5DF2\u5B58\u5728\uFF0C\u5C06\u8986\u76D6\uFF09",
1150
+ "zh-TW": "{0}\uFF08\u5DF2\u5B58\u5728\uFF0C\u5C07\u8986\u84CB\uFF09",
1151
+ "en-US": "{0} (exists, will be overwritten)"
1152
+ },
1153
+ // 问句里不带项目名:清单第一行就是它
1154
+ "confirm.create": {
1155
+ "zh-CN": "\u521B\u5EFA Quicksilver \u9879\u76EE",
1156
+ "zh-TW": "\u5EFA\u7ACB Quicksilver \u5C08\u6848",
1157
+ "en-US": "Create the Quicksilver project"
1158
+ },
1159
+ "error.directoryExists": {
1160
+ "zh-CN": "\u300C{0}\u300D\u5DF2\u5B58\u5728\u3002--yes \u4E0D\u4F1A\u8986\u76D6\u5DF2\u6709\u7684\u6587\u4EF6\u6216\u76EE\u5F55\uFF0C\u8BF7\u5220\u9664\u5B83\u6216\u6362\u4E00\u4E2A\u9879\u76EE\u540D",
1161
+ "zh-TW": "\u300C{0}\u300D\u5DF2\u5B58\u5728\u3002--yes \u4E0D\u6703\u8986\u84CB\u65E2\u6709\u7684\u6A94\u6848\u6216\u76EE\u9304\uFF0C\u8ACB\u522A\u9664\u5B83\u6216\u63DB\u4E00\u500B\u5C08\u6848\u540D",
1162
+ "en-US": '"{0}" already exists. --yes never overwrites it. Remove it or pick another name'
1163
+ },
1164
+ "error.directoryAppeared": {
1165
+ "zh-CN": "\u300C{0}\u300D\u662F\u521A\u521A\u624D\u51FA\u73B0\u7684\uFF0C\u6CA1\u6709\u52A8\u5B83\u3002\u8BF7\u5220\u9664\u5B83\u6216\u6362\u4E00\u4E2A\u9879\u76EE\u540D",
1166
+ "zh-TW": "\u300C{0}\u300D\u662F\u525B\u525B\u624D\u51FA\u73FE\u7684\uFF0C\u6C92\u6709\u52D5\u5B83\u3002\u8ACB\u522A\u9664\u5B83\u6216\u63DB\u4E00\u500B\u5C08\u6848\u540D",
1167
+ "en-US": '"{0}" showed up just now and was left alone. Remove it or pick another name'
1168
+ },
1169
+ "confirm.overwrite": {
1170
+ "zh-CN": "\u300C{0}\u300D\u5DF2\u5B58\u5728\uFF0C\u8986\u76D6\u5B83",
1171
+ "zh-TW": "\u300C{0}\u300D\u5DF2\u5B58\u5728\uFF0C\u8986\u84CB\u5B83",
1172
+ "en-US": '"{0}" already exists. Overwrite it'
1173
+ },
1174
+ "progress.creating": { "zh-CN": "\u6B63\u5728\u521B\u5EFA\u9879\u76EE\u2026", "zh-TW": "\u6B63\u5728\u5EFA\u7ACB\u5C08\u6848\u2026", "en-US": "Creating project..." },
1175
+ "progress.succeeded": {
1176
+ "zh-CN": "Quicksilver \u9879\u76EE\u521B\u5EFA\u5B8C\u6210\uFF01",
1177
+ "zh-TW": "Quicksilver \u5C08\u6848\u5EFA\u7ACB\u5B8C\u6210\uFF01",
1178
+ "en-US": "Quicksilver project created successfully!"
1179
+ },
1180
+ "progress.failed": {
1181
+ "zh-CN": "\u9879\u76EE\u521B\u5EFA\u5931\u8D25",
1182
+ "zh-TW": "\u5C08\u6848\u5EFA\u7ACB\u5931\u6557",
1183
+ "en-US": "Failed to create project"
1184
+ },
1185
+ "progress.nextSteps": { "zh-CN": "\u63A5\u4E0B\u6765\uFF1A", "zh-TW": "\u63A5\u4E0B\u4F86\uFF1A", "en-US": "Next steps:" },
1186
+ "progress.setup": {
1187
+ "zh-CN": "\u5B89\u88C5\u4F9D\u8D56\u4E4B\u524D\uFF0C\u8BF7\u9996\u5148\u9605\u8BFB `{0}`\uFF0C\u8BBE\u7F6E Quicksilver \u7684 Nexus \u5730\u5740\u4E0E\u767B\u5F55\u65B9\u5F0F\u3002",
1188
+ "zh-TW": "\u5B89\u88DD\u76F8\u4F9D\u5957\u4EF6\u4E4B\u524D\uFF0C\u8ACB\u5148\u95B1\u8B80 `{0}`\uFF0C\u8A2D\u5B9A Quicksilver \u7684 Nexus \u4F4D\u5740\u8207\u767B\u5165\u65B9\u5F0F\u3002",
1189
+ "en-US": "Before installing dependencies, read `{0}` first to set up the address and login for Quicksilver's Nexus."
1190
+ },
1191
+ "progress.git": {
1192
+ "zh-CN": "\u5EFA\u8BAE\u7B2C\u4E00\u65F6\u95F4\u5BF9\u9879\u76EE\u8FDB\u884C\u7248\u672C\u63A7\u5236\uFF1A",
1193
+ "zh-TW": "\u5EFA\u8B70\u7B2C\u4E00\u6642\u9593\u5C07\u5C08\u6848\u7D0D\u5165\u7248\u672C\u63A7\u5236\uFF1A",
1194
+ "en-US": "Put the project under version control right away (recommended):"
1195
+ },
1196
+ // 刻意不翻:这一句是收尾的招呼,三种语言都用同一句。留在目录里是为了走同一条渲染路径,
1197
+ // 但不要「顺手把它译了」
1198
+ "progress.happy": {
1199
+ "zh-CN": "Happy coding! \u{1F389}\n",
1200
+ "zh-TW": "Happy coding! \u{1F389}\n",
1201
+ "en-US": "Happy coding! \u{1F389}\n"
1202
+ }
1203
+ };
1204
+ var catalog = createCatalog(TEXTS);
1205
+ var language = catalog.language;
1206
+ var t = catalog.t;
1207
+ function applyPromptTexts() {
1208
+ setPromptLanguage(language);
1209
+ }
1210
+ function printHint2(step) {
1211
+ printHint(HINTS[step][language]);
1212
+ }
1213
+
1214
+ // src/collect/summary.ts
1215
+ function row(step, value) {
1216
+ return { label: t(`label.${step}`), value };
1217
+ }
1218
+ function summaryRows(options) {
1219
+ return [
1220
+ row("projectName", options.name),
1221
+ {
1222
+ label: t("summary.projectPath"),
1223
+ value: options.overwrite ? t("summary.projectPathOverwrite", shortenHome(options.projectPath)) : shortenHome(options.projectPath)
1224
+ },
1225
+ row("moduleDirectory", options.moduleDirectory),
1226
+ row("moduleCode", options.moduleCode),
1227
+ row("moduleNamespace", options.moduleNamespace ?? ""),
1228
+ row("apiPackage", options.apiPackage),
1229
+ row("apiArtifactId", options.apiArtifactId),
1230
+ row("webModulePackage", options.webModulePackage),
1231
+ row("platformModules", options.platformModules.join(", ")),
1232
+ { label: t("label.moduleMenuName"), value: options.moduleMenu ?? t("summary.noMenu") }
1233
+ ];
1234
+ }
1235
+
1236
+ // src/utils/namespaces.ts
1237
+ function matchesNamespacePattern(pattern, namespace) {
1238
+ const source = [...pattern].map(toRegExpSource).join("");
1239
+ return new RegExp(`^${source}$`).test(namespace);
1240
+ }
1241
+ function toRegExpSource(ch) {
1242
+ switch (ch) {
1243
+ case "?":
1244
+ return ".";
1245
+ case "*":
1246
+ return ".*";
1247
+ default:
1248
+ return ch.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1249
+ }
1250
+ }
1251
+
1252
+ // src/utils/platform-modules.ts
1253
+ var MAVEN_GROUP = "com.qsrun";
1254
+ var PLATFORM_MODULE_PREFIX = "quicksilver.";
1255
+ var PLATFORM_NAMESPACES = {
1256
+ ac: "quicksilver.core",
1257
+ ao: "quicksilver.org",
1258
+ acs: "quicksilver.sample"
1259
+ };
1260
+ var PLATFORM_RESERVED_NAMESPACES = ["a?"];
1261
+ var PLATFORM_MODULES = [
1262
+ {
1263
+ code: "quicksilver.core",
1264
+ description: "module.core",
1265
+ required: true,
1266
+ apiArtifactId: "quicksilver-module-core",
1267
+ webPackage: "@qs-platform/web-module-core"
1268
+ },
1269
+ {
1270
+ code: "quicksilver.org",
1271
+ description: "module.org",
1272
+ dependencies: ["quicksilver.core"],
1273
+ apiArtifactId: "quicksilver-module-org",
1274
+ webPackage: "@qs-platform/web-module-org"
1275
+ }
1276
+ ];
1277
+ var moduleMap = new Map(PLATFORM_MODULES.map((module) => [module.code, module]));
1278
+ function getRequiredModuleCodes() {
1279
+ return PLATFORM_MODULES.filter((module) => module.required).map((module) => module.code);
1280
+ }
1281
+ function resolvePlatformModules(codes) {
1282
+ const selected = /* @__PURE__ */ new Set([...getRequiredModuleCodes(), ...codes]);
1283
+ const addDependencies = (code) => {
1284
+ moduleMap.get(code)?.dependencies?.forEach((dependency) => {
1285
+ if (!selected.has(dependency)) {
1286
+ selected.add(dependency);
1287
+ addDependencies(dependency);
1288
+ }
1289
+ });
1290
+ };
1291
+ [...selected].forEach(addDependencies);
1292
+ return PLATFORM_MODULES.filter((module) => selected.has(module.code));
1293
+ }
1294
+ function parsePlatformModuleCodes(input) {
1295
+ const codes = input.split(",").map((code) => code.trim()).filter(Boolean);
1296
+ const unknown = codes.filter((code) => !moduleMap.has(code));
1297
+ if (unknown.length > 0) {
1298
+ const available = PLATFORM_MODULES.map((module) => module.code).join(", ");
1299
+ throw new UsageError(`Unknown platform module(s): ${unknown.join(", ")}. Available: ${available}`);
1300
+ }
1301
+ return resolvePlatformModules(codes).map((module) => module.code);
1302
+ }
1303
+ function buildPlatformModuleVariables(codes) {
1304
+ const modules = resolvePlatformModules(codes);
1305
+ return {
1306
+ PLATFORM_MODULE_CODES: modules.map((m) => m.code).join(","),
1307
+ PLATFORM_MODULE_CODES_QUOTED: modules.map((m) => `'${m.code}'`).join(", "),
1308
+ PLATFORM_MODULE_DEPENDENCIES: modules.map((m) => `{ code: ${m.code} }`).join("\n - "),
1309
+ PLATFORM_API_DEPENDENCIES: modules.map((m) => `api("${MAVEN_GROUP}:${m.apiArtifactId}")`).join("\n "),
1310
+ PLATFORM_WEB_DEPENDENCIES: modules.map((m) => `"${m.webPackage}": "catalog:quicksilver"`).join(",\n "),
1311
+ PLATFORM_WEB_IMPORTS: modules.map((m) => `'${m.code}': () => import('${m.webPackage}/module'),`).join("\n ")
1312
+ };
1313
+ }
1314
+
1315
+ // src/collect/naming.ts
1316
+ var SPECS = {
1317
+ projectName: {
1318
+ check: (v) => checkKebab(v, { min: 2, max: 32 }),
1319
+ charset: "naming.charset.kebab",
1320
+ separator: "hyphen",
1321
+ leading: "letter"
1322
+ },
1323
+ moduleDirectory: {
1324
+ check: (v) => checkKebab(v, { min: 2, max: 32 }),
1325
+ charset: "naming.charset.kebab",
1326
+ separator: "hyphen",
1327
+ leading: "letter"
1328
+ },
1329
+ moduleCode: {
1330
+ check: (v) => checkSnakeSegments(v, { max: 50, minSegments: 2 }),
1331
+ charset: "naming.charset.snakeSegments",
1332
+ separator: "underscoreOrDot",
1333
+ leading: "letter"
1334
+ },
1335
+ moduleNamespace: {
1336
+ check: (v) => checkAlnum(v, { min: 2, max: 10 }),
1337
+ charset: "naming.charset.alnum",
1338
+ separator: "hyphen",
1339
+ leading: "letter"
1340
+ },
1341
+ apiPackage: {
1342
+ check: (v) => checkJavaPackage(v, { max: 64 }),
1343
+ charset: "naming.charset.javaPackage",
1344
+ separator: "dot",
1345
+ leading: "letter"
1346
+ },
1347
+ apiArtifactId: {
1348
+ check: (v) => checkKebab(v, { min: 2, max: 64 }),
1349
+ charset: "naming.charset.kebab",
1350
+ separator: "hyphen",
1351
+ leading: "letter"
1352
+ },
1353
+ webModulePackage: {
1354
+ check: (v) => checkNpmPackage(v, { max: 64 }),
1355
+ charset: "naming.charset.npm",
1356
+ separator: "hyphen",
1357
+ leading: "alnum"
1358
+ }
1359
+ };
1360
+ function validateName(kind, value) {
1361
+ const spec = SPECS[kind];
1362
+ const title = t(`label.${kind}`);
1363
+ const result = spec.check(value);
1364
+ if (!result) {
1365
+ if (kind === "moduleCode" && value.startsWith(PLATFORM_MODULE_PREFIX)) {
1366
+ return t("naming.reservedPrefix", title);
1367
+ }
1368
+ if (kind === "moduleNamespace") {
1369
+ return platformNamespaceError(title, value) ?? true;
1370
+ }
1371
+ return true;
1372
+ }
1373
+ switch (result.violation) {
1374
+ case "empty":
1375
+ return t("validate.empty", title);
1376
+ case "tooShort":
1377
+ return t("naming.tooShort", title, result.limit);
1378
+ case "tooLong":
1379
+ return t("validate.tooLong", title, result.limit);
1380
+ case "charset":
1381
+ return t(spec.charset, title);
1382
+ case "controlChars":
1383
+ return t("validate.controlChars", title);
1384
+ case "leadingLetter":
1385
+ return t(spec.leading === "alnum" ? "naming.leadingAlnum" : "naming.leadingLetter", title);
1386
+ case "segmentLeadingLetter":
1387
+ return t("naming.segmentLeadingLetter", title);
1388
+ case "trailingSeparator":
1389
+ return t("naming.trailingSeparator", title, t(`sep.end.${spec.separator}`));
1390
+ case "doubleSeparator":
1391
+ return t("naming.doubleSeparator", title, t(`sep.pair.${spec.separator}`));
1392
+ case "segments":
1393
+ return t("naming.segments", title, result.limit);
1394
+ case "keyword":
1395
+ return t("naming.keyword", title);
1396
+ }
1397
+ }
1398
+ function platformNamespaceError(title, value) {
1399
+ if (Object.hasOwn(PLATFORM_NAMESPACES, value)) {
1400
+ return t("naming.platformNamespace", title, value, PLATFORM_NAMESPACES[value]);
1401
+ }
1402
+ const pattern = PLATFORM_RESERVED_NAMESPACES.find((it) => matchesNamespacePattern(it, value));
1403
+ return pattern === void 0 ? void 0 : t("naming.platformPattern", title, value, pattern);
1404
+ }
1405
+
1406
+ // src/collect/collect-options.ts
1407
+ function kebabToSnakeCase(str) {
1408
+ return str.replace(/-/g, "_");
1409
+ }
1410
+ function removeHyphen(str) {
1411
+ return str.replace(/-/g, "");
1412
+ }
1413
+ function initialsOf(code) {
1414
+ return code.split(/[._]/).map((word) => word.charAt(0)).join("");
1415
+ }
1416
+ var FLAGS = {
1417
+ projectName: "<project-name>",
1418
+ moduleDirectory: "--module-directory",
1419
+ moduleCode: "--module-code",
1420
+ moduleNamespace: "--module-namespace",
1421
+ apiPackage: "--api-package",
1422
+ apiArtifactId: "--api-artifact-id",
1423
+ webModulePackage: "--web-module-package",
1424
+ platformModules: "--modules",
1425
+ moduleMenu: "--module-menu"
1426
+ };
1427
+ async function ask(args, step, options) {
1428
+ if (args.yes) {
1429
+ const error = await options.validate?.(options.initial);
1430
+ if (typeof error === "string") {
1431
+ throw new UsageError(t("validate.badDefault", error, options.initial, FLAGS[step]));
1432
+ }
1433
+ return options.initial;
1434
+ }
1435
+ printHint2(step);
1436
+ return inputText(options);
1437
+ }
1438
+ function revalidate(value, validate) {
1439
+ const error = validate(value);
1440
+ if (typeof error === "string") {
1441
+ throw new UsageError(error);
1442
+ }
1443
+ return value;
1444
+ }
1445
+ async function collectProjectName(args) {
1446
+ const validate = (s) => validateName("projectName", s);
1447
+ const value = args.name ?? await ask(args, "projectName", {
1448
+ message: t("label.projectName"),
1449
+ initial: "my-project",
1450
+ validate
1451
+ });
1452
+ return revalidate(value, validate);
1453
+ }
1454
+ async function confirmOverwrite(args, options) {
1455
+ if (!await fs6.pathExists(options.projectPath)) {
1456
+ return false;
1457
+ }
1458
+ if (args.yes) {
1459
+ throw new UsageError(t("error.directoryExists", options.name));
1460
+ }
1461
+ Message.blankLine();
1462
+ if (!await inputBoolean(t("confirm.overwrite", options.name))) {
1463
+ throw new PromptCancelled();
1464
+ }
1465
+ return true;
1466
+ }
1467
+ async function collectModuleDirectory(args) {
1468
+ const validate = (s) => validateName("moduleDirectory", s);
1469
+ const value = args.moduleDirectory ?? await ask(args, "moduleDirectory", {
1470
+ message: t("label.moduleDirectory"),
1471
+ initial: "main",
1472
+ validate
1473
+ });
1474
+ return revalidate(value, validate);
1475
+ }
1476
+ async function collectModuleCode(args, options) {
1477
+ const validate = (s) => validateName("moduleCode", s);
1478
+ const value = args.moduleCode ?? await ask(args, "moduleCode", {
1479
+ message: t("label.moduleCode"),
1480
+ initial: `${kebabToSnakeCase(options.name)}.${kebabToSnakeCase(options.moduleDirectory)}`,
1481
+ validate
1482
+ });
1483
+ return revalidate(value, validate);
1484
+ }
1485
+ async function collectModuleNamespace(args, options) {
1486
+ const validate = (s) => validateName("moduleNamespace", s);
1487
+ const value = args.moduleNamespace ?? await ask(args, "moduleNamespace", {
1488
+ message: t("label.moduleNamespace"),
1489
+ initial: initialsOf(options.moduleCode),
1490
+ validate
1491
+ });
1492
+ return revalidate(value, validate);
1493
+ }
1494
+ async function collectApiPackage(args, options) {
1495
+ const validate = (s) => validateName("apiPackage", s);
1496
+ const value = args.apiPackage ?? await ask(args, "apiPackage", {
1497
+ message: t("label.apiPackage"),
1498
+ initial: `com.company.${removeHyphen(options.name)}`,
1499
+ validate
1500
+ });
1501
+ return revalidate(value, validate);
1502
+ }
1503
+ async function collectApiArtifactId(args, options) {
1504
+ const validate = (input) => validateName("apiArtifactId", input);
1505
+ const value = args.apiArtifactId ?? await ask(args, "apiArtifactId", {
1506
+ message: t("label.apiArtifactId"),
1507
+ initial: `${options.name}-module-${options.moduleDirectory}`,
1508
+ validate
1509
+ });
1510
+ return revalidate(value, validate);
1511
+ }
1512
+ async function collectWebModulePackage(args, options) {
1513
+ const validate = (s) => validateName("webModulePackage", s);
1514
+ const value = args.webModulePackage ?? await ask(args, "webModulePackage", {
1515
+ message: t("label.webModulePackage"),
1516
+ initial: `@${options.name}/module-${options.moduleDirectory}-web`,
1517
+ validate
1518
+ });
1519
+ return revalidate(value, validate);
1520
+ }
1521
+ async function collectPlatformModules(args) {
1522
+ if (args.modules !== void 0) {
1523
+ const validate = (s) => s.split(",").some((code) => code.trim()) ? true : t("validate.empty", t("label.platformModules"));
1524
+ return parsePlatformModuleCodes(revalidate(args.modules, validate));
1525
+ }
1526
+ if (args.yes) {
1527
+ return getRequiredModuleCodes();
1528
+ }
1529
+ printHint2("platformModules");
1530
+ const items = PLATFORM_MODULES.map((module) => ({
1531
+ name: `${module.code} \u2014 ${t(module.description)}${module.required ? t("module.required") : ""}`,
1532
+ value: module.code,
1533
+ checked: module.required,
1534
+ disabled: module.required,
1535
+ dependencies: module.dependencies
1536
+ }));
1537
+ const codes = await multiselect({ message: t("label.platformModules"), items });
1538
+ return resolvePlatformModules(codes).map((module) => module.code);
1539
+ }
1540
+ async function collectModuleMenu(args, options) {
1541
+ if (args.moduleMenu === false) {
1542
+ return void 0;
1543
+ }
1544
+ const validate = (s) => {
1545
+ const title = t("label.moduleMenuName");
1546
+ switch (checkDisplayName(s, { max: 50 })?.violation) {
1547
+ // ac_web_menu.name 的列宽
1548
+ case void 0:
1549
+ return true;
1550
+ case "empty":
1551
+ return t("validate.empty", title);
1552
+ case "controlChars":
1553
+ return t("validate.controlChars", title);
1554
+ default:
1555
+ return t("validate.tooLong", title, 50);
1556
+ }
1557
+ };
1558
+ if (typeof args.moduleMenu === "string") {
1559
+ return revalidate(args.moduleMenu, validate).trim();
1560
+ }
1561
+ if (args.yes) {
1562
+ return options.name;
1563
+ }
1564
+ printHint2("moduleMenu");
1565
+ if (!await inputBoolean(t("label.moduleMenu"), true)) {
1566
+ return void 0;
1567
+ }
1568
+ const value = await inputText({
1569
+ message: t("label.moduleMenuName"),
1570
+ initial: options.name,
1571
+ validate
1572
+ });
1573
+ return revalidate(value, validate).trim();
1574
+ }
1575
+ async function collectProjectOptions(args) {
1576
+ const options = {};
1577
+ options.name = await collectProjectName(args);
1578
+ options.projectPath = path5.resolve(process.cwd(), options.name);
1579
+ options.overwrite = await confirmOverwrite(args, options);
1580
+ options.moduleDirectory = await collectModuleDirectory(args);
1581
+ options.moduleCode = await collectModuleCode(args, options);
1582
+ options.moduleNamespace = await collectModuleNamespace(args, options);
1583
+ options.apiPackage = await collectApiPackage(args, options);
1584
+ options.apiArtifactId = await collectApiArtifactId(args, options);
1585
+ options.webModulePackage = await collectWebModulePackage(args, options);
1586
+ options.platformModules = await collectPlatformModules(args);
1587
+ options.moduleMenu = await collectModuleMenu(args, options);
1588
+ options.template = "default";
1589
+ printSummary(t("summary.title"), summaryRows(options));
1590
+ if (!args.yes) {
1591
+ Message.blankLine();
1592
+ if (!await inputBoolean(t("confirm.create"), options.overwrite ? void 0 : true)) {
1593
+ throw new PromptCancelled();
1594
+ }
1595
+ }
1596
+ return options;
1597
+ }
1598
+ var FileEntry = class {
1599
+ constructor(path7, type) {
1600
+ this.path = path7;
1601
+ this.type = type;
1602
+ }
1603
+ path;
1604
+ type;
1605
+ fileContent;
1606
+ get content() {
1607
+ this.fileContent ??= fs3.readFileSync(this.path, "utf8");
1608
+ return this.fileContent;
1609
+ }
1610
+ set content(content) {
1611
+ this.fileContent = content;
1612
+ }
1613
+ flush() {
1614
+ if (typeof this.fileContent === "string") {
1615
+ fs3.writeFileSync(this.path, this.fileContent, "utf8");
1616
+ }
1617
+ }
1618
+ };
1619
+
1620
+ // src/create/processors/base-processor.ts
1621
+ var BaseProcessor = class {
1622
+ };
1623
+
1624
+ // src/create/processors/extension-processor.ts
1625
+ var ExtensionProcessor = class extends BaseProcessor {
1626
+ name = "extension-processor";
1627
+ accept(entry) {
1628
+ return entry.type !== "directory" && (entry.path.endsWith(".tpl.txt") || entry.path.endsWith(".tpl.bin"));
1629
+ }
1630
+ async process(entry) {
1631
+ const newPath = entry.path.replace(/\.tpl\.(bin|txt)$/, "");
1632
+ await fs6.move(entry.path, newPath, { overwrite: true });
1633
+ entry.path = newPath;
1634
+ }
1635
+ };
1636
+ var PlaceholderProcessor = class extends BaseProcessor {
1637
+ constructor(options, variables) {
1638
+ super();
1639
+ this.options = options;
1640
+ this.variables = variables;
1641
+ }
1642
+ options;
1643
+ variables;
1644
+ name = "placeholder-processor";
1645
+ textExtensions = new Set("html,js,json,jsons,kt,kts,md,properties,ts,tsx,txt,yaml,yml".split(","));
1646
+ specialTextFiles = /* @__PURE__ */ new Set([
1647
+ "org.springframework.boot.autoconfigure.AutoConfiguration.imports"
1648
+ ]);
1649
+ accept(entry) {
1650
+ return this.isPlaceholderInFileName(entry) || this.isTextFile(entry);
1651
+ }
1652
+ async process(entry) {
1653
+ if (this.isPlaceholderInFileName(entry)) {
1654
+ const fileName = path5.basename(entry.path);
1655
+ const newFileName = this.replacePlaceholders(fileName, "path");
1656
+ if (newFileName !== fileName) {
1657
+ const parts = newFileName === this.options.apiPackage ? newFileName.split(".") : [newFileName];
1658
+ const newPath = path5.join(path5.dirname(entry.path), ...parts);
1659
+ await fs6.move(entry.path, newPath, { overwrite: true });
1660
+ entry.path = newPath;
1661
+ }
1662
+ }
1663
+ if (this.isTextFile(entry)) {
1664
+ entry.content = this.replacePlaceholders(entry.content, "content");
1665
+ }
1666
+ }
1667
+ isPlaceholderInFileName(entry) {
1668
+ return /\{\{([a-zA-Z0-9_]+)}}/.test(path5.basename(entry.path));
1669
+ }
1670
+ isTextFile(entry) {
1671
+ if (entry.type !== "file") {
1672
+ return false;
1673
+ } else if (this.specialTextFiles.has(path5.basename(entry.path))) {
1674
+ return true;
1675
+ }
1676
+ const ext = path5.extname(entry.path);
1677
+ return !!ext && this.textExtensions.has(ext.substring(1));
1678
+ }
1679
+ replacePlaceholders(text, context) {
1680
+ return text.replace(/\{\{([a-zA-Z0-9_]+)}}/g, (match, key) => {
1681
+ if (this.variables.has(key)) {
1682
+ return String(this.variables.get(key));
1683
+ } else {
1684
+ const contextText = context === "path" ? "Path placeholder" : "Placeholder";
1685
+ Message.warn(`${contextText} '{{${key}}}' not found, keeping original text.`);
1686
+ return match;
1687
+ }
1688
+ });
1689
+ }
1690
+ };
1691
+ var SORT_ORDER = 3;
1692
+ var ICON = "quicksilver:module-work";
1693
+ function renderModuleMenu(name) {
1694
+ if (!name) {
1695
+ return { text: "" };
1696
+ }
1697
+ const menuId = randomUUID();
1698
+ const text = [
1699
+ "",
1700
+ "// The module's top-level menu: a first-level entry in the left nav that this",
1701
+ "// module's pages hang under.",
1702
+ `// Shift the existing top-level entries down by one and take slot ${SORT_ORDER}: after`,
1703
+ "// the built-in \u65E5\u5E38 (1) and, when the org module is installed, \u7EC4\u7EC7 (2); the remaining",
1704
+ "// built-in ones sit beyond 1000.",
1705
+ `{ @sql: "update ac_web_menu set sort_order = sort_order + 1 where parent_id is null and sort_order >= ${SORT_ORDER}" }`,
1706
+ "",
1707
+ "{ $insert: 'ac.web_menu' }",
1708
+ `{ id: '${menuId}', name: ${literal(name)}, icon: '${ICON}', sort_order: ${SORT_ORDER} }`,
1709
+ // 模板里 MODULE_MENU 占位符是最后一个字符,没有换行跟在后面——不建菜单时文件就干净地
1710
+ // 停在模块那一行,建了才由这里补上收尾的换行
1711
+ ""
1712
+ ].join("\n");
1713
+ return { text, menuId };
1714
+ }
1715
+
1716
+ // src/create/create-project.ts
1717
+ async function prepareTarget({ name, projectPath, overwrite }) {
1718
+ if (!await fs6.pathExists(projectPath)) {
1719
+ return;
1720
+ }
1721
+ if (!overwrite) {
1722
+ throw new UsageError(t("error.directoryAppeared", name));
1723
+ }
1724
+ await fs6.remove(projectPath);
1725
+ }
1726
+ var SETUP_CHAPTER = "00-setup.md";
1727
+ async function createProject(options) {
1728
+ const { name, template, projectPath } = options;
1729
+ await prepareTarget(options);
1730
+ Message.blankLine();
1731
+ Message.info(t("progress.creating"));
1732
+ try {
1733
+ const templatePath = getTemplatePath(template);
1734
+ await fs6.copy(templatePath, projectPath);
1735
+ await restoreExecutables(projectPath);
1736
+ await restoreDotFiles(projectPath);
1737
+ await processFiles(options);
1738
+ const setupPath = manualChapterPath(projectPath, SETUP_CHAPTER, language);
1739
+ Message.blankLine();
1740
+ Message.iconSuccess(t("progress.succeeded"));
1741
+ printNextSteps(name, setupPath, !isInsideGitRepository(projectPath));
1742
+ } catch (error) {
1743
+ Message.error(t("progress.failed"));
1744
+ throw error;
1745
+ }
1746
+ }
1747
+ function printNextSteps(name, setupPath, suggestGit) {
1748
+ Message.blankLine();
1749
+ Message.info(t("progress.nextSteps"));
1750
+ Message.hint(` cd ${name}`);
1751
+ Message.hint(" pnpm i");
1752
+ Message.hint(" pnpm dev");
1753
+ printHint(t("progress.setup", setupPath));
1754
+ if (suggestGit) {
1755
+ Message.info(t("progress.git"));
1756
+ Message.hint(" git init");
1757
+ Message.hint(" git add -A");
1758
+ Message.hint(' git commit -m "Initial commit"');
1759
+ Message.blankLine();
1760
+ }
1761
+ Message.hint(t("progress.happy"));
1762
+ }
1763
+ function isInsideGitRepository(dir) {
1764
+ for (let current = path5.resolve(dir); ; current = path5.dirname(current)) {
1765
+ if (fs6.existsSync(path5.join(current, ".git"))) {
1766
+ return true;
1767
+ }
1768
+ if (path5.dirname(current) === current) {
1769
+ return false;
1770
+ }
1771
+ }
1772
+ }
1773
+ var EXECUTABLES = ["gradlew"];
1774
+ async function restoreExecutables(projectPath) {
1775
+ for (const file of EXECUTABLES) {
1776
+ await fs6.chmod(path5.join(projectPath, file), 493);
1777
+ }
1778
+ }
1779
+ var DOT_FILES = { _gitignore: ".gitignore" };
1780
+ async function restoreDotFiles(projectPath) {
1781
+ for (const [stored, real] of Object.entries(DOT_FILES)) {
1782
+ await fs6.move(path5.join(projectPath, stored), path5.join(projectPath, real), { overwrite: true });
1783
+ }
1784
+ }
1785
+ function getTemplatePath(template) {
1786
+ const dir = path5.dirname(fileURLToPath(import.meta.url));
1787
+ const templateDir = path5.join(dir, "template", template);
1788
+ if (!fs6.existsSync(templateDir)) {
1789
+ throw new Error(`Template "${template}" not found. dir: ${templateDir}`);
1790
+ }
1791
+ return templateDir;
1792
+ }
1793
+ var processors = [];
1794
+ function toDbPrefix(name) {
1795
+ return name.replace(/-/g, "_");
1796
+ }
1797
+ async function processFiles(options) {
1798
+ const variables = /* @__PURE__ */ new Map();
1799
+ variables.set("PROJECT_CODE", options.name);
1800
+ variables.set("MODULE_CODE", options.moduleCode);
1801
+ variables.set("MODULE_DIRECTORY", options.moduleDirectory);
1802
+ variables.set("MODULE_NAMESPACE", options.moduleNamespace);
1803
+ variables.set("WEB_PACKAGE_NAME", options.webModulePackage);
1804
+ variables.set("API_PACKAGE", options.apiPackage);
1805
+ variables.set("API_ARTIFACT_ID", options.apiArtifactId);
1806
+ variables.set("QUICKSILVER_VERSION", "0.8.21");
1807
+ variables.set("MODULE_ID", randomUUID());
1808
+ variables.set("DB_PREFIX", toDbPrefix(options.name));
1809
+ const menu = renderModuleMenu(options.moduleMenu);
1810
+ variables.set("MODULE_MENU", menu.text);
1811
+ variables.set("MODULE_DEFAULT_MENU", menu.menuId ? `default_menu_id: '${menu.menuId}', ` : "");
1812
+ for (const [key, value] of Object.entries(buildPlatformModuleVariables(options.platformModules))) {
1813
+ variables.set(key, value);
1814
+ }
1815
+ processors.push(new ExtensionProcessor());
1816
+ processors.push(new PlaceholderProcessor(options, variables));
1817
+ await walk(options.projectPath);
1818
+ }
1819
+ async function walk(dir) {
1820
+ const files = await fs6.readdir(dir);
1821
+ for (const file of files) {
1822
+ const filePath = path5.join(dir, file);
1823
+ const stat = await fs6.stat(filePath);
1824
+ const entry = new FileEntry(filePath, stat.isDirectory() ? "directory" : "file");
1825
+ for (const processor of processors) {
1826
+ if (processor.accept(entry)) {
1827
+ await processor.process(entry);
1828
+ }
1829
+ }
1830
+ entry.flush();
1831
+ if (entry.type === "directory") {
1832
+ await walk(entry.path);
1833
+ }
1834
+ }
1835
+ }
1836
+ function reportFailure(error) {
1837
+ if (isPromptCancelled(error)) {
1838
+ printCancelled(t("cancelled"));
1839
+ return 0;
1840
+ }
1841
+ if (error instanceof UsageError) {
1842
+ console.error(chalkStderr.red(`
1843
+ \u2716 ${error.message}
1844
+ `));
1845
+ return 1;
1846
+ }
1847
+ console.error(error);
1848
+ console.log();
1849
+ return 1;
1850
+ }
1851
+
1852
+ // src/index.ts
1853
+ function getCliVersion() {
1854
+ const dir = path5__default.dirname(fileURLToPath(import.meta.url));
1855
+ const pkgPath = path5__default.join(dir, "package.json");
1856
+ if (fs3__default.existsSync(pkgPath)) {
1857
+ const pkg = JSON.parse(fs3__default.readFileSync(pkgPath, "utf-8"));
1858
+ if (pkg.version) {
1859
+ return pkg.version;
1860
+ }
1861
+ }
1862
+ return "0.0.0";
1863
+ }
1864
+ if (process.argv.some((arg) => arg === "--version" || arg === "-v")) {
1865
+ console.log(getCliVersion());
1866
+ process.exit(0);
1867
+ }
1868
+ var program = new Command().name("create-qs").description("Create a new Quicksilver application").version("0.8.21", "-v, --version").argument("[project-name]", "Name of the project").option("-c, --module-code <code>", "Full module code (e.g., power_crm.sales)").option("-d, --module-directory <directory>", "Module directory name (e.g., sales)").option("-n, --module-namespace <code>", "Prefix of unit/table, defaults to the initials of the module code (e.g., pcs)").option("-p, --api-package <package>", "JVM package for Kotlin files (e.g., com.company.crm)").option("-a, --api-artifact-id <artifactId>", "Module artifact ID in repository (e.g., power-crm-module-sales)").option("-w, --web-module-package <package>", "Web module package name (e.g., @powercrm/module-sales-web)").option("-m, --modules <codes>", "Modules to depend on, comma separated (e.g., quicksilver.org)").option("--module-menu <name>", "Create the module's top-level menu in the left nav, with this label").option("--no-module-menu", "Do not create a top-level menu").option("-y, --yes", "Skip prompts and use defaults").action(async (projectName, options) => {
1869
+ applyPromptTexts();
1870
+ console.log(chalk4.cyan(`
1871
+ ${t("banner")}`));
1872
+ try {
1873
+ options.name = projectName;
1874
+ const projectOptions = await collectProjectOptions(options);
1875
+ await createProject(projectOptions);
1876
+ } catch (error) {
1877
+ const code = reportFailure(error);
1878
+ if (code !== 0) {
1879
+ process.exit(code);
1880
+ }
1881
+ }
1882
+ });
1883
+ program.parse();