esa-cli 0.0.2-beta.2 → 0.0.2-beta.20

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 (82) hide show
  1. package/dist/commands/commit/index.js +48 -115
  2. package/dist/commands/commit/prodBuild.js +2 -3
  3. package/dist/commands/common/constant.js +0 -19
  4. package/dist/commands/common/utils.js +416 -0
  5. package/dist/commands/config.js +1 -1
  6. package/dist/commands/deploy/helper.js +51 -72
  7. package/dist/commands/deploy/index.js +50 -188
  8. package/dist/commands/deployments/delete.js +32 -22
  9. package/dist/commands/deployments/index.js +2 -2
  10. package/dist/commands/deployments/list.js +22 -38
  11. package/dist/commands/dev/build.js +3 -3
  12. package/dist/commands/dev/doProcess.js +5 -5
  13. package/dist/commands/dev/ew2/cacheService.js +33 -0
  14. package/dist/commands/dev/ew2/devEntry.js +2 -1
  15. package/dist/commands/dev/ew2/devPack.js +39 -43
  16. package/dist/commands/dev/ew2/kvService.js +27 -0
  17. package/dist/commands/dev/ew2/mock/cache.js +99 -15
  18. package/dist/commands/dev/ew2/mock/kv.js +142 -21
  19. package/dist/commands/dev/ew2/server.js +165 -29
  20. package/dist/commands/dev/index.js +17 -17
  21. package/dist/commands/dev/mockWorker/devPack.js +35 -24
  22. package/dist/commands/dev/mockWorker/server.js +7 -6
  23. package/dist/commands/domain/add.js +2 -2
  24. package/dist/commands/domain/delete.js +7 -7
  25. package/dist/commands/domain/index.js +2 -2
  26. package/dist/commands/domain/list.js +10 -10
  27. package/dist/commands/init/helper.js +759 -0
  28. package/dist/commands/init/index.js +88 -220
  29. package/dist/commands/init/snippets/nextjs/next.config.mjs +6 -0
  30. package/dist/commands/init/snippets/nextjs/next.config.ts +7 -0
  31. package/dist/commands/init/snippets/react-router/react-router.config.ts +7 -0
  32. package/dist/commands/init/template.jsonc +84 -0
  33. package/dist/commands/init/types.js +1 -0
  34. package/dist/commands/lang.js +2 -2
  35. package/dist/commands/login/index.js +74 -34
  36. package/dist/commands/logout.js +5 -5
  37. package/dist/commands/route/add.js +105 -49
  38. package/dist/commands/route/delete.js +33 -27
  39. package/dist/commands/route/helper.js +123 -0
  40. package/dist/commands/route/index.js +2 -2
  41. package/dist/commands/route/list.js +56 -17
  42. package/dist/commands/routine/delete.js +2 -2
  43. package/dist/commands/routine/index.js +2 -2
  44. package/dist/commands/routine/list.js +43 -37
  45. package/dist/commands/site/index.js +1 -1
  46. package/dist/commands/site/list.js +6 -7
  47. package/dist/commands/utils.js +59 -23
  48. package/dist/components/descriptionInput.js +1 -1
  49. package/dist/components/filterSelector.js +1 -1
  50. package/dist/components/mutiLevelSelect.js +43 -55
  51. package/dist/components/mutiSelectTable.js +1 -1
  52. package/dist/components/routeBuilder.js +68 -0
  53. package/dist/components/selectInput.js +2 -3
  54. package/dist/components/selectItem.js +1 -1
  55. package/dist/docs/Commands_en.md +142 -131
  56. package/dist/docs/Commands_zh_CN.md +139 -127
  57. package/dist/i18n/index.js +2 -2
  58. package/dist/i18n/locales.json +435 -23
  59. package/dist/index.js +27 -20
  60. package/dist/libs/api.js +32 -9
  61. package/dist/libs/apiService.js +267 -88
  62. package/dist/libs/git/index.js +86 -9
  63. package/dist/libs/interface.js +0 -1
  64. package/dist/libs/logger.js +162 -10
  65. package/dist/libs/service.js +2 -2
  66. package/dist/libs/templates/index.js +3 -2
  67. package/dist/utils/checkAssetsExist.js +80 -0
  68. package/dist/utils/checkDevPort.js +3 -17
  69. package/dist/utils/checkEntryFileExist.js +10 -0
  70. package/dist/utils/checkIsRoutineCreated.js +28 -27
  71. package/dist/utils/checkVersion.js +119 -1
  72. package/dist/utils/command.js +149 -0
  73. package/dist/utils/compress.js +136 -0
  74. package/dist/utils/download.js +182 -0
  75. package/dist/utils/fileMd5.js +1 -1
  76. package/dist/utils/fileUtils/base.js +1 -1
  77. package/dist/utils/fileUtils/index.js +136 -44
  78. package/dist/utils/installDeno.js +8 -8
  79. package/dist/utils/installEw2.js +7 -7
  80. package/dist/utils/openInBrowser.js +1 -1
  81. package/dist/utils/prompt.js +97 -0
  82. package/package.json +19 -12
@@ -7,60 +7,66 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- var __rest = (this && this.__rest) || function (s, e) {
11
- var t = {};
12
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
13
- t[p] = s[p];
14
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
15
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
16
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
17
- t[p[i]] = s[p[i]];
18
- }
19
- return t;
20
- };
10
+ import chalk from 'chalk';
21
11
  import Table from 'cli-table3';
12
+ import moment from 'moment';
13
+ import t from '../../i18n/index.js';
14
+ import { ApiService } from '../../libs/apiService.js';
22
15
  import logger from '../../libs/logger.js';
23
- import { Base64 } from 'js-base64';
24
16
  import { checkIsLoginSuccess } from '../utils.js';
25
- import chalk from 'chalk';
26
- import { ApiService } from '../../libs/apiService.js';
27
- import t from '../../i18n/index.js';
28
- import moment from 'moment';
29
17
  const list = {
30
18
  command: 'list',
31
19
  describe: `📋 ${t('list_describe').d('List all your routines')}`,
32
20
  builder: (yargs) => {
33
- return yargs.usage(`${t('common_usage').d('Usage')}: \$0 list []`);
21
+ return yargs
22
+ .option('keyword', {
23
+ alias: 'k',
24
+ describe: t('deploy_option_keyword').d('Keyword to search for routines'),
25
+ type: 'string'
26
+ })
27
+ .usage(`${t('common_usage').d('Usage')}: \$0 list [--keyword <keyword>]`);
34
28
  },
35
29
  handler: (argv) => __awaiter(void 0, void 0, void 0, function* () {
36
30
  handleList(argv);
37
31
  })
38
32
  };
39
33
  export default list;
40
- export function handleList(argv) {
34
+ export function getAllRoutines(options) {
41
35
  return __awaiter(this, void 0, void 0, function* () {
42
36
  var _a;
43
- const { site } = argv, args = __rest(argv, ["site"]);
37
+ const server = yield ApiService.getInstance();
38
+ const allRoutines = [];
39
+ let pageNumber = 1;
40
+ const pageSize = (options === null || options === void 0 ? void 0 : options.PageSize) || 50;
41
+ while (true) {
42
+ const res = yield server.listUserRoutines({
43
+ RegionId: options === null || options === void 0 ? void 0 : options.RegionId,
44
+ PageNumber: pageNumber,
45
+ PageSize: pageSize,
46
+ SearchKeyWord: options === null || options === void 0 ? void 0 : options.SearchKeyWord
47
+ });
48
+ if (!((_a = res === null || res === void 0 ? void 0 : res.body) === null || _a === void 0 ? void 0 : _a.Routines)) {
49
+ break;
50
+ }
51
+ allRoutines.push(...res.body.Routines);
52
+ const totalCount = res.body.TotalCount;
53
+ const currentCount = allRoutines.length;
54
+ if (currentCount >= totalCount) {
55
+ break;
56
+ }
57
+ pageNumber++;
58
+ }
59
+ return allRoutines;
60
+ });
61
+ }
62
+ export function handleList(argv) {
63
+ return __awaiter(this, void 0, void 0, function* () {
44
64
  const isSuccess = yield checkIsLoginSuccess();
45
65
  if (!isSuccess)
46
66
  return;
47
- const server = yield ApiService.getInstance();
48
- if (site) {
49
- const req = {
50
- SiteSearchType: 'fuzzy',
51
- Status: 'active',
52
- PageNumber: 1,
53
- PageSize: 50
54
- };
55
- const res = yield server.listSites(req);
56
- const siteList = (_a = res === null || res === void 0 ? void 0 : res.data.Sites) !== null && _a !== void 0 ? _a : [];
57
- const siteNameList = siteList === null || siteList === void 0 ? void 0 : siteList.map((item) => item.SiteName);
58
- logger.log(chalk.bold.bgGray(`📃 ${t('list_site_name_title').d('List all of site names')}:`));
59
- logger.tree(siteNameList);
60
- return;
61
- }
62
- const res = yield server.getRoutineUserInfo();
63
- const routineList = res === null || res === void 0 ? void 0 : res.Routines;
67
+ const routineList = yield getAllRoutines({
68
+ SearchKeyWord: argv.keyword
69
+ });
64
70
  if (routineList) {
65
71
  logger.log(chalk.bold.bgGray(`📃 ${t('list_routine_name_title').d('List all of routine')}:`));
66
72
  displayRoutineList(routineList);
@@ -77,7 +83,7 @@ export function displayRoutineList(versionList) {
77
83
  table.push([
78
84
  version.RoutineName,
79
85
  moment(version.CreateTime).format('YYYY/MM/DD HH:mm:ss'),
80
- Base64.decode(version.Description)
86
+ version.Description
81
87
  ]);
82
88
  });
83
89
  console.table(table.toString());
@@ -1,5 +1,5 @@
1
- import siteList from './list.js';
2
1
  import t from '../../i18n/index.js';
2
+ import siteList from './list.js';
3
3
  let yargsIns;
4
4
  const siteCommand = {
5
5
  command: 'site [script]',
@@ -7,25 +7,24 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import logger from '../../libs/logger.js';
11
- import { checkIsLoginSuccess } from '../utils.js';
12
10
  import chalk from 'chalk';
13
- import { ApiService } from '../../libs/apiService.js';
14
11
  import t from '../../i18n/index.js';
12
+ import { ApiService } from '../../libs/apiService.js';
13
+ import logger from '../../libs/logger.js';
14
+ import { checkIsLoginSuccess } from '../utils.js';
15
15
  const list = {
16
16
  command: 'list',
17
17
  describe: `📋 ${t('site_describe_list').d('List all your sites')}`,
18
18
  builder: (yargs) => {
19
19
  return yargs.usage(`${t('common_usage').d('Usage')}: \$0 list []`);
20
20
  },
21
- handler: (argv) => __awaiter(void 0, void 0, void 0, function* () {
22
- handleList(argv);
21
+ handler: () => __awaiter(void 0, void 0, void 0, function* () {
22
+ handleList();
23
23
  })
24
24
  };
25
25
  export default list;
26
- export function handleList(argv) {
26
+ export function handleList() {
27
27
  return __awaiter(this, void 0, void 0, function* () {
28
- // const { site, ...args } = argv;
29
28
  var _a;
30
29
  const isSuccess = yield checkIsLoginSuccess();
31
30
  if (!isSuccess)
@@ -7,15 +7,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import fs from 'fs';
11
10
  import { execSync } from 'child_process';
12
- import { isInstalledGit } from '../libs/git/index.js';
13
- import { getCliConfig, projectConfigPath } from '../utils/fileUtils/index.js';
14
- import { getRoot } from '../utils/fileUtils/base.js';
11
+ import fs from 'fs';
15
12
  import chalk from 'chalk';
16
13
  import t from '../i18n/index.js';
14
+ import api from '../libs/api.js';
17
15
  import { ApiService } from '../libs/apiService.js';
16
+ import { isInstalledGit } from '../libs/git/index.js';
18
17
  import logger from '../libs/logger.js';
18
+ import { getRoot } from '../utils/fileUtils/base.js';
19
+ import { getCliConfig, projectConfigPath } from '../utils/fileUtils/index.js';
20
+ import { getRoutineDetails } from './common/utils.js';
19
21
  export const checkDirectory = (isCheckGit = false) => {
20
22
  const root = getRoot();
21
23
  if (fs.existsSync(projectConfigPath)) {
@@ -66,51 +68,75 @@ export const bindRoutineWithDomain = (name, domain) => __awaiter(void 0, void 0,
66
68
  logger.error(t('utils_domain_error').d('Domain is not active'));
67
69
  }
68
70
  });
69
- export const getRoutineVersionList = (name) => __awaiter(void 0, void 0, void 0, function* () {
70
- var _a;
71
- const server = yield ApiService.getInstance();
72
- const req = { Name: name };
73
- const res = yield server.getRoutine(req);
74
- return ((_a = res === null || res === void 0 ? void 0 : res.data) === null || _a === void 0 ? void 0 : _a.CodeVersions) || [];
75
- });
76
71
  export function validName(name) {
77
72
  return /^[a-zA-Z0-9-_]+$/.test(name);
78
73
  }
79
- // 校验域名是否有效
74
+ // Validate if domain is valid
80
75
  export function validDomain(domain) {
81
76
  return /^(?:[a-z0-9-](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/.test(domain);
82
77
  }
83
78
  export function checkIsLoginSuccess() {
84
79
  return __awaiter(this, void 0, void 0, function* () {
80
+ var _a, _b;
81
+ let accessKeyId = process.env.ESA_ACCESS_KEY_ID;
82
+ let accessKeySecret = process.env.ESA_ACCESS_KEY_SECRET;
83
+ let endpoint = process.env.ESA_ENDPOINT;
85
84
  const cliConfig = getCliConfig();
86
- const namedCommand = chalk.green('esa login');
87
- if (!cliConfig || !cliConfig.auth) {
88
- return false;
85
+ if (!accessKeyId || !accessKeySecret) {
86
+ accessKeyId = (_a = cliConfig === null || cliConfig === void 0 ? void 0 : cliConfig.auth) === null || _a === void 0 ? void 0 : _a.accessKeyId;
87
+ accessKeySecret = (_b = cliConfig === null || cliConfig === void 0 ? void 0 : cliConfig.auth) === null || _b === void 0 ? void 0 : _b.accessKeySecret;
88
+ }
89
+ if (!endpoint) {
90
+ endpoint = cliConfig === null || cliConfig === void 0 ? void 0 : cliConfig.endpoint;
89
91
  }
90
- if (!cliConfig.auth.accessKeyId || !cliConfig.auth.accessKeySecret) {
92
+ const namedCommand = chalk.green('esa login');
93
+ if (!accessKeyId || !accessKeySecret) {
91
94
  logger.log(`❌ ${t('utils_login_error').d('Maybe you are not logged in yet.')}`);
92
95
  logger.log(`🔔 ${t('utils_login_error_config', { namedCommand }).d(`Please run command to login: ${namedCommand}`)}`);
93
96
  return false;
94
97
  }
98
+ return yield validateLoginCredentials(accessKeyId, accessKeySecret, endpoint, namedCommand);
99
+ });
100
+ }
101
+ /**
102
+ * 验证登录凭据的公共函数
103
+ * @param accessKeyId AccessKey ID
104
+ * @param accessKeySecret AccessKey Secret
105
+ * @param namedCommand 命令名称(用于错误提示)
106
+ * @param showError 是否显示错误信息
107
+ * @returns 登录是否成功
108
+ */
109
+ export function validateLoginCredentials(accessKeyId_1, accessKeySecret_1, endpoint_1, namedCommand_1) {
110
+ return __awaiter(this, arguments, void 0, function* (accessKeyId, accessKeySecret, endpoint, namedCommand, showError = true) {
95
111
  const server = yield ApiService.getInstance();
96
- server.updateConfig(cliConfig);
112
+ server.updateConfig({
113
+ auth: {
114
+ accessKeyId,
115
+ accessKeySecret
116
+ },
117
+ endpoint: endpoint
118
+ });
97
119
  const res = yield server.checkLogin();
98
120
  if (res.success) {
99
121
  return true;
100
122
  }
101
- logger.log(res.message || '');
102
- logger.log(`❌ ${t('utils_login_error').d('Maybe you are not logged in yet.')}`);
103
- logger.log(`🔔 ${t('utils_login_error_config', { namedCommand }).d(`Please run command to login: ${namedCommand}`)}`);
123
+ if (showError) {
124
+ logger.log(res.message || '');
125
+ logger.log(`❌ ${t('utils_login_error').d('Maybe you are not logged in yet.')}`);
126
+ if (namedCommand) {
127
+ logger.log(`🔔 ${t('utils_login_error_config', { namedCommand }).d(`Please run command to login: ${namedCommand}`)}`);
128
+ }
129
+ }
104
130
  return false;
105
131
  });
106
132
  }
107
133
  export function isValidRouteForDomain(route, domain) {
108
- // 构建一个允许子域和任意路径的正则表达式
109
- // 例如,匹配形式如 *.example.com/* 的URL
134
+ // Build a regex that allows subdomains and arbitrary paths
135
+ // For example, match URLs like *.example.com/*
110
136
  return route.includes(domain);
111
137
  }
112
138
  export function escapeRegExp(string) {
113
- return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& 表示整个被匹配的字符串
139
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& represents the entire matched string
114
140
  }
115
141
  export const getAllSites = () => __awaiter(void 0, void 0, void 0, function* () {
116
142
  var _a;
@@ -138,3 +164,13 @@ export const getAllSites = () => __awaiter(void 0, void 0, void 0, function* ()
138
164
  };
139
165
  });
140
166
  });
167
+ export const getRoutineCodeVersions = (projectName) => __awaiter(void 0, void 0, void 0, function* () {
168
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
169
+ const routineDetail = yield getRoutineDetails(projectName);
170
+ const req = { name: projectName };
171
+ const res = yield api.listRoutineCodeVersions(req);
172
+ const allVersions = (_b = (_a = res.body) === null || _a === void 0 ? void 0 : _a.codeVersions) !== null && _b !== void 0 ? _b : [];
173
+ const stagingVersions = ((_g = (_f = (_e = (_d = (_c = routineDetail === null || routineDetail === void 0 ? void 0 : routineDetail.data) === null || _c === void 0 ? void 0 : _c.Envs) === null || _d === void 0 ? void 0 : _d.find((item) => item.Env === 'staging')) === null || _e === void 0 ? void 0 : _e.CodeDeploy) === null || _f === void 0 ? void 0 : _f.CodeVersions) === null || _g === void 0 ? void 0 : _g.map((item) => item.CodeVersion)) || [];
174
+ const productionVersions = ((_m = (_l = (_k = (_j = (_h = routineDetail === null || routineDetail === void 0 ? void 0 : routineDetail.data) === null || _h === void 0 ? void 0 : _h.Envs) === null || _j === void 0 ? void 0 : _j.find((item) => item.Env === 'production')) === null || _k === void 0 ? void 0 : _k.CodeDeploy) === null || _l === void 0 ? void 0 : _l.CodeVersions) === null || _m === void 0 ? void 0 : _m.map((item) => item.CodeVersion)) || [];
175
+ return { allVersions, stagingVersions, productionVersions };
176
+ });
@@ -7,9 +7,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import React, { useState } from 'react';
11
10
  import { Box, render, Text } from 'ink';
12
11
  import TextInput from 'ink-text-input';
12
+ import React, { useState } from 'react';
13
13
  export const DescriptionInput = ({ prompt, onSubmit, required }) => {
14
14
  const [input, setInput] = useState('');
15
15
  const [error, setError] = useState('');
@@ -51,7 +51,7 @@ export const FilterSelector = ({ data, onSubmit, hideCount = 20 }) => {
51
51
  else if (tabPressCount === 1) {
52
52
  const filteredDataInner = data.filter((site) => site.label.includes(inputValue));
53
53
  setFilteredData(filteredDataInner);
54
- // 匹配结果大于等于1个时,进入选择模式
54
+ // Enter selection mode when match results >= 1
55
55
  if ((filteredDataInner.length >= 1 &&
56
56
  showAll &&
57
57
  filteredDataInner.length > hideCount) ||
@@ -7,63 +7,51 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import React, { useState } from 'react';
11
- import { render, Text, useApp } from 'ink';
12
- import SelectInput from 'ink-select-input';
13
- import Item from './selectItem.js';
14
- import t from '../i18n/index.js';
15
- const Indicator = ({ isSelected }) => {
16
- return React.createElement(Text, null, isSelected ? '👉 ' : ' ');
17
- };
18
- const EXIT_ITEM = {
19
- label: t('exit_select_init_template').d('Exit'),
20
- key: 'exit',
21
- value: '__exit__'
22
- };
23
- const RETURN_ITEM = {
24
- label: t('return_select_init_template').d('Return'),
25
- key: 'return',
26
- value: '__return__'
27
- };
28
- const MultiLevelSelect = ({ items, handleSelect, handleExit }) => {
29
- const { exit } = useApp();
30
- const [stack, setStack] = useState([[...items, EXIT_ITEM]]);
31
- const currentItems = stack[stack.length - 1];
32
- const onSelect = (item) => {
33
- if (item.value === '__return__') {
34
- if (stack.length > 1) {
35
- // 返回上一级菜单
36
- setStack(stack.slice(0, -1));
10
+ import { isCancel, select as clackSelect } from '@clack/prompts';
11
+ import logger from '../libs/logger.js';
12
+ /**
13
+ * Perform multi-level selection and return the final selected template path
14
+ * @param items Array of selection items (including categories and sub-templates)
15
+ * @param message Initial prompt message
16
+ * @returns Selected template path, or null if the user exits
17
+ */
18
+ export default function multiLevelSelect(items_1) {
19
+ return __awaiter(this, arguments, void 0, function* (items, message = 'Select a template:') {
20
+ let currentItems = items; // Current level options
21
+ const stack = []; // Stack to store previous level options for back navigation
22
+ let selectedPath = null;
23
+ while (selectedPath === null) {
24
+ const choice = (yield clackSelect({
25
+ message,
26
+ options: [
27
+ ...currentItems.map((item) => ({
28
+ label: item.label,
29
+ value: item.value,
30
+ hint: item.hint
31
+ })),
32
+ ...(stack.length > 0 ? [{ label: 'Back', value: '__back__' }] : [])
33
+ ]
34
+ }));
35
+ if (isCancel(choice)) {
36
+ logger.log('User canceled the operation.');
37
+ return null;
38
+ }
39
+ if (choice === '__back__') {
40
+ currentItems = stack.pop(); // Return to the previous level
41
+ continue;
42
+ }
43
+ // If a category with children is selected
44
+ const selected = currentItems.find((i) => i.value === choice);
45
+ if (selected && selected.children && selected.children.length > 0) {
46
+ stack.push(currentItems); // Save the current level
47
+ currentItems = selected.children; // Move to the next level
48
+ message = `Select a template under ${selected.label}:`;
37
49
  }
38
50
  else {
39
- // 顶层菜单,执行退出逻辑
40
- handleExit();
41
- exit();
51
+ // A leaf node (no children) is selected, end the selection
52
+ selectedPath = choice;
42
53
  }
43
- return;
44
- }
45
- if (item.children && item.children.length > 0) {
46
- setStack([...stack, [...item.children, RETURN_ITEM]]); // 在子层级中添加“退出”选项
47
54
  }
48
- else {
49
- handleSelect(item);
50
- exit();
51
- }
52
- };
53
- return (React.createElement(SelectInput, { items: currentItems, onSelect: onSelect, itemComponent: Item, indicatorComponent: Indicator, limit: 10 }));
54
- };
55
- export const MultiLevelSelectComponent = (props) => __awaiter(void 0, void 0, void 0, function* () {
56
- const { items, handleSelect, handleExit } = props;
57
- return new Promise((resolve) => {
58
- const { unmount } = render(React.createElement(MultiLevelSelect, { items: items, handleSelect: (item) => {
59
- unmount();
60
- handleSelect && handleSelect(item);
61
- resolve(item);
62
- }, handleExit: () => {
63
- unmount();
64
- handleExit && handleExit();
65
- resolve(null);
66
- } }));
55
+ return selectedPath;
67
56
  });
68
- });
69
- export default MultiLevelSelectComponent;
57
+ }
@@ -7,8 +7,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import React, { useState } from 'react';
11
10
  import { Box, render, Text, useInput } from 'ink';
11
+ import React, { useState } from 'react';
12
12
  import t from '../i18n/index.js';
13
13
  export const MultiSelectTable = ({ items, itemsPerRow, onSubmit, boxWidth = 25 }) => {
14
14
  const [selectedIndexes, setSelectedIndexes] = useState(new Set());
@@ -0,0 +1,68 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { Box, render, Text } from 'ink';
11
+ import TextInput from 'ink-text-input';
12
+ import React, { useState } from 'react';
13
+ import t from '../i18n/index.js';
14
+ export const RouteBuilder = ({ siteName, onSubmit, onCancel }) => {
15
+ const [prefix, setPrefix] = useState('');
16
+ const [suffix, setSuffix] = useState('');
17
+ const [currentInput, setCurrentInput] = useState('prefix');
18
+ const [error, setError] = useState('');
19
+ const handleSubmit = () => {
20
+ if (currentInput === 'prefix') {
21
+ setCurrentInput('suffix');
22
+ return;
23
+ }
24
+ // Build complete route, add dot before prefix and slash before suffix if not empty
25
+ const prefixWithDot = prefix ? `${prefix}.` : '';
26
+ const suffixWithDot = suffix ? `/${suffix}` : '';
27
+ const route = `${prefixWithDot}${siteName}${suffixWithDot}`;
28
+ onSubmit(route);
29
+ };
30
+ const handleCancel = () => {
31
+ onCancel();
32
+ };
33
+ const currentPrompt = currentInput === 'prefix'
34
+ ? t('route_builder_prefix_prompt')
35
+ .d(`Enter route prefix for ${siteName} (e.g., abc, def):`)
36
+ .replace('${siteName}', siteName)
37
+ : t('route_builder_suffix_prompt')
38
+ .d(`Enter route suffix for ${siteName} (e.g., *, users/*):`)
39
+ .replace('${siteName}', siteName);
40
+ const prefixWithDot = prefix ? `${prefix}.` : '';
41
+ const suffixWithDot = suffix ? `/${suffix}` : '';
42
+ const preview = `Preview: ${prefixWithDot}${siteName}${suffixWithDot}`;
43
+ return (React.createElement(Box, { flexDirection: "column" },
44
+ React.createElement(Box, null,
45
+ React.createElement(Text, null, "Building route for site: "),
46
+ React.createElement(Text, { color: "cyan" }, siteName)),
47
+ React.createElement(Box, { marginTop: 1 },
48
+ React.createElement(Text, null, currentPrompt)),
49
+ React.createElement(Box, { marginTop: 1 },
50
+ React.createElement(TextInput, { value: currentInput === 'prefix' ? prefix : suffix, onChange: currentInput === 'prefix' ? setPrefix : setSuffix, onSubmit: handleSubmit })),
51
+ preview && (React.createElement(Box, { marginTop: 1 },
52
+ React.createElement(Text, { color: "green" }, preview))),
53
+ React.createElement(Box, { marginTop: 1 },
54
+ React.createElement(Text, { color: "gray" }, t('route_builder_instructions').d('Press Enter to continue, Ctrl+C to cancel'))),
55
+ error && (React.createElement(Box, { marginTop: 1 },
56
+ React.createElement(Text, { color: "red" }, error)))));
57
+ };
58
+ export const routeBuilder = (siteName) => __awaiter(void 0, void 0, void 0, function* () {
59
+ return new Promise((resolve) => {
60
+ const { unmount } = render(React.createElement(RouteBuilder, { siteName: siteName, onSubmit: (route) => {
61
+ unmount();
62
+ resolve(route);
63
+ }, onCancel: () => {
64
+ unmount();
65
+ resolve(null);
66
+ } }));
67
+ });
68
+ });
@@ -1,7 +1,6 @@
1
- import React from 'react';
2
- import { render } from 'ink';
1
+ import { render, Text } from 'ink';
3
2
  import SelectInput from 'ink-select-input';
4
- import { Text } from 'ink';
3
+ import React from 'react';
5
4
  import Item from './selectItem.js';
6
5
  const Indicator = ({ isSelected }) => {
7
6
  return React.createElement(Text, null, isSelected ? '👉 ' : ' ');
@@ -1,5 +1,5 @@
1
- import * as React from 'react';
2
1
  import { Text } from 'ink';
2
+ import * as React from 'react';
3
3
  function Item({ isSelected = false, label }) {
4
4
  return React.createElement(Text, { color: isSelected ? 'green' : undefined }, label);
5
5
  }