esa-cli 0.0.2-beta.10 → 0.0.2-beta.13

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 (75) hide show
  1. package/dist/commands/commit/index.js +26 -115
  2. package/dist/commands/commit/prodBuild.js +2 -3
  3. package/dist/commands/common/routineUtils.js +276 -0
  4. package/dist/commands/config.js +1 -1
  5. package/dist/commands/deploy/helper.js +40 -61
  6. package/dist/commands/deploy/index.js +90 -188
  7. package/dist/commands/deployments/delete.js +32 -22
  8. package/dist/commands/deployments/index.js +2 -2
  9. package/dist/commands/deployments/list.js +22 -38
  10. package/dist/commands/dev/build.js +3 -3
  11. package/dist/commands/dev/doProcess.js +5 -5
  12. package/dist/commands/dev/ew2/cacheService.js +33 -0
  13. package/dist/commands/dev/ew2/devEntry.js +2 -1
  14. package/dist/commands/dev/ew2/devPack.js +22 -11
  15. package/dist/commands/dev/ew2/kvService.js +27 -0
  16. package/dist/commands/dev/ew2/mock/cache.js +99 -15
  17. package/dist/commands/dev/ew2/mock/kv.js +142 -21
  18. package/dist/commands/dev/ew2/server.js +162 -27
  19. package/dist/commands/dev/index.js +14 -15
  20. package/dist/commands/dev/mockWorker/devPack.js +16 -7
  21. package/dist/commands/dev/mockWorker/server.js +7 -6
  22. package/dist/commands/domain/add.js +2 -2
  23. package/dist/commands/domain/delete.js +7 -7
  24. package/dist/commands/domain/index.js +2 -2
  25. package/dist/commands/domain/list.js +10 -10
  26. package/dist/commands/init/helper.js +87 -13
  27. package/dist/commands/init/index.js +461 -57
  28. package/dist/commands/init/template.jsonc +34 -0
  29. package/dist/commands/lang.js +2 -2
  30. package/dist/commands/login/index.js +57 -7
  31. package/dist/commands/logout.js +5 -5
  32. package/dist/commands/route/add.js +138 -49
  33. package/dist/commands/route/delete.js +33 -27
  34. package/dist/commands/route/helper.js +124 -0
  35. package/dist/commands/route/index.js +2 -2
  36. package/dist/commands/route/list.js +56 -17
  37. package/dist/commands/routine/delete.js +2 -2
  38. package/dist/commands/routine/index.js +2 -2
  39. package/dist/commands/routine/list.js +9 -21
  40. package/dist/commands/site/index.js +1 -1
  41. package/dist/commands/site/list.js +6 -7
  42. package/dist/commands/utils.js +55 -19
  43. package/dist/components/descriptionInput.js +1 -1
  44. package/dist/components/mutiSelectTable.js +1 -1
  45. package/dist/components/selectInput.js +2 -3
  46. package/dist/components/selectItem.js +1 -1
  47. package/dist/docs/Commands_en.md +25 -15
  48. package/dist/docs/Commands_zh_CN.md +12 -2
  49. package/dist/docs/eslint-config-en.md +1 -0
  50. package/dist/docs/eslint-config.md +73 -0
  51. package/dist/docs/init-command-quick-test.md +208 -0
  52. package/dist/docs/init-command-test-guide.md +598 -0
  53. package/dist/i18n/index.js +2 -2
  54. package/dist/i18n/locales.json +261 -17
  55. package/dist/index.js +17 -12
  56. package/dist/libs/api.js +32 -9
  57. package/dist/libs/apiService.js +258 -85
  58. package/dist/libs/git/index.js +8 -4
  59. package/dist/libs/interface.js +0 -1
  60. package/dist/libs/logger.js +63 -7
  61. package/dist/libs/service.js +2 -2
  62. package/dist/libs/templates/index.js +1 -1
  63. package/dist/utils/checkAssetsExist.js +80 -0
  64. package/dist/utils/checkDevPort.js +3 -17
  65. package/dist/utils/checkEntryFileExist.js +10 -0
  66. package/dist/utils/checkIsRoutineCreated.js +16 -31
  67. package/dist/utils/checkVersion.js +1 -1
  68. package/dist/utils/compress.js +80 -0
  69. package/dist/utils/download.js +5 -5
  70. package/dist/utils/fileMd5.js +1 -1
  71. package/dist/utils/fileUtils/index.js +71 -22
  72. package/dist/utils/installDeno.js +3 -3
  73. package/dist/utils/installEw2.js +7 -7
  74. package/dist/utils/openInBrowser.js +1 -1
  75. package/package.json +11 -6
@@ -7,30 +7,65 @@ 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-extra';
10
+ import { execSync } from 'child_process';
11
11
  import path from 'path';
12
- import inquirer from 'inquirer';
13
12
  import { exit } from 'process';
14
- import Template from '../../libs/templates/index.js';
15
- import { installGit } from '../../libs/git/index.js';
13
+ import fs from 'fs-extra';
14
+ import inquirer from 'inquirer';
16
15
  import multiLevelSelect from '../../components/mutiLevelSelect.js';
17
- import { generateConfigFile, getCliConfig, getProjectConfig, getTemplatesConfig, templateHubPath, updateProjectConfigFile } from '../../utils/fileUtils/index.js';
18
16
  import t from '../../i18n/index.js';
17
+ import { installGit } from '../../libs/git/index.js';
19
18
  import logger from '../../libs/logger.js';
20
- import { quickDeploy } from '../deploy/index.js';
21
- import { ApiService } from '../../libs/apiService.js';
22
- import { checkRoutineExist } from '../../utils/checkIsRoutineCreated.js';
23
- import { checkIsLoginSuccess } from '../utils.js';
24
- import chalk from 'chalk';
25
- import { checkAndUpdatePackage, getTemplateInstances, preInstallDependencies, transferTemplatesToSelectItem } from './helper.js';
19
+ import Template from '../../libs/templates/index.js';
20
+ import { generateConfigFile, getCliConfig, getProjectConfig, getTemplatesConfig, templateHubPath, updateProjectConfigFile } from '../../utils/fileUtils/index.js';
21
+ import { quickDeployForInit } from '../common/routineUtils.js';
22
+ import { checkAndUpdatePackage, getAllFrameworkConfig, getFrameworkConfig, getTemplateInstances, preInstallDependencies, transferTemplatesToSelectItem } from './helper.js';
26
23
  const init = {
27
- command: 'init',
24
+ command: 'init [name]',
28
25
  describe: `📥 ${t('init_describe').d('Initialize a routine with a template')}`,
29
26
  builder: (yargs) => {
30
- return yargs.option('config', {
27
+ return yargs
28
+ .positional('name', {
29
+ describe: t('init_project_name').d('Project name'),
30
+ type: 'string'
31
+ })
32
+ .option('framework', {
33
+ alias: 'f',
34
+ describe: 'Choose a frontend framework (react/vue/nextjs)',
35
+ type: 'string',
36
+ choices: ['react', 'vue', 'nextjs']
37
+ })
38
+ .option('language', {
39
+ alias: 'l',
40
+ describe: 'Choose programming language (typescript/javascript)',
41
+ type: 'string',
42
+ choices: ['typescript', 'javascript']
43
+ })
44
+ .option('template', {
45
+ alias: 't',
46
+ describe: t('init_template_name').d('Template name to use'),
47
+ type: 'string'
48
+ })
49
+ .option('config', {
31
50
  alias: 'c',
32
51
  describe: t('init_config_file').d('Generate a config file for your project'),
33
52
  type: 'boolean'
53
+ })
54
+ .option('templateParams', {
55
+ describe: 'Generate a global template-params config file',
56
+ type: 'boolean'
57
+ })
58
+ .option('yes', {
59
+ alias: 'y',
60
+ describe: t('init_yes').d('Answer "Yes" to all prompts.'),
61
+ type: 'boolean',
62
+ default: false
63
+ })
64
+ .option('skip', {
65
+ alias: 's',
66
+ describe: t('init_skip').d('Answer "No" to any prompts for new projects.'),
67
+ type: 'boolean',
68
+ default: false
34
69
  });
35
70
  },
36
71
  handler: (argv) => __awaiter(void 0, void 0, void 0, function* () {
@@ -39,13 +74,45 @@ const init = {
39
74
  })
40
75
  };
41
76
  export default init;
77
+ export function findTemplatePathByName(templateName) {
78
+ const templateInstanceList = getTemplateInstances(templateHubPath);
79
+ const templateConfig = getTemplatesConfig();
80
+ // find template recursively
81
+ function findTemplateRecursive(configs) {
82
+ for (const config of configs) {
83
+ const title = config.Title_EN;
84
+ if (title === templateName) {
85
+ const template = templateInstanceList.find((template) => {
86
+ return config.Title_EN === template.title;
87
+ });
88
+ return (template === null || template === void 0 ? void 0 : template.path) || null;
89
+ }
90
+ }
91
+ return null;
92
+ }
93
+ return findTemplateRecursive(templateConfig);
94
+ }
95
+ export function validateProjectName(name) {
96
+ const regex = /^[a-z0-9-]{2,}$/;
97
+ return regex.test(name);
98
+ }
42
99
  export function promptProjectName() {
43
- return __awaiter(this, void 0, void 0, function* () {
100
+ return __awaiter(this, arguments, void 0, function* (yes = false) {
101
+ if (yes) {
102
+ // Generate a default name when --yes is used
103
+ const defaultName = `edge-routine-${Date.now()}`;
104
+ logger.log(`${t('init_input_name').d('Enter the name of edgeRoutine:')} ${defaultName}`);
105
+ logger.replacePrevLines(2, `├ ${t('init_input_name').d('Enter the name of edgeRoutine')}`);
106
+ logger.cfStepKV('name', defaultName);
107
+ logger.cfStepSpacer();
108
+ return defaultName;
109
+ }
44
110
  const { name } = yield inquirer.prompt([
45
111
  {
46
112
  type: 'input',
47
113
  name: 'name',
48
- message: `🖊️ ${t('init_input_name').d('Enter the name of edgeRoutine:')}`,
114
+ message: `${t('init_input_name').d('Enter the name of edgeRoutine:')}\n`,
115
+ prefix: '╰',
49
116
  validate: (input) => {
50
117
  const regex = /^[a-z0-9-]{2,}$/;
51
118
  if (!regex.test(input)) {
@@ -55,6 +122,9 @@ export function promptProjectName() {
55
122
  }
56
123
  }
57
124
  ]);
125
+ logger.replacePrevLines(2, `├ ${t('init_input_name').d('Enter the name of edgeRoutine:')}`);
126
+ logger.cfStepKV('ER Name', name);
127
+ logger.cfStepSpacer();
58
128
  return name;
59
129
  });
60
130
  }
@@ -66,8 +136,21 @@ export function prepareTemplateItems() {
66
136
  const lang = (_a = cliConfig === null || cliConfig === void 0 ? void 0 : cliConfig.lang) !== null && _a !== void 0 ? _a : 'en';
67
137
  return transferTemplatesToSelectItem(templateConfig, templateInstanceList, lang);
68
138
  }
69
- export function selectTemplate(items) {
70
- return __awaiter(this, void 0, void 0, function* () {
139
+ export function selectTemplate(items_1) {
140
+ return __awaiter(this, arguments, void 0, function* (items, yes = false) {
141
+ if (yes) {
142
+ // Select the first available template when --yes is used
143
+ const firstTemplate = items[0];
144
+ if (firstTemplate) {
145
+ logger.log(`Select a template: ${firstTemplate.label}`);
146
+ return firstTemplate.value;
147
+ }
148
+ else {
149
+ logger.error(t('init_no_templates').d('No templates available.'));
150
+ return null;
151
+ }
152
+ }
153
+ logger.cfStepEnd();
71
154
  const selectedTemplatePath = yield multiLevelSelect(items, 'Select a template:');
72
155
  if (!selectedTemplatePath) {
73
156
  logger.log(t('init_cancel').d('User canceled the operation.'));
@@ -96,30 +179,236 @@ export function initializeProject(selectedTemplatePath, name) {
96
179
  return { template: selectTemplate, targetPath };
97
180
  });
98
181
  }
99
- export function handleGitInitialization(targetPath) {
100
- return __awaiter(this, void 0, void 0, function* () {
182
+ export function handleGitInitialization(targetPath_1) {
183
+ return __awaiter(this, arguments, void 0, function* (targetPath, yes = false) {
184
+ if (yes) {
185
+ logger.log(`${t('init_git').d('Do you want to init git in your project?')} Yes`);
186
+ installGit(targetPath);
187
+ return;
188
+ }
101
189
  const { initGit } = yield inquirer.prompt([
102
190
  {
103
191
  type: 'list',
104
192
  name: 'initGit',
105
193
  message: t('init_git').d('Do you want to init git in your project?'),
194
+ prefix: '╰',
106
195
  choices: ['Yes', 'No']
107
196
  }
108
197
  ]);
198
+ logger.replacePrevLine('├ Do you want to init git in your project?');
109
199
  if (initGit === 'Yes') {
110
- installGit(targetPath);
200
+ const success = installGit(targetPath);
201
+ if (success) {
202
+ logger.cfStepKV('git', t('git_installed_success').d('Git has been installed successfully.'));
203
+ logger.cfStepSpacer();
204
+ }
111
205
  }
112
206
  else {
113
- logger.log(t('init_skip_git').d('Git installation was skipped.'));
207
+ logger.cfStepKV('git', t('init_skip_git').d('Git installation was skipped.'));
208
+ logger.cfStepSpacer();
114
209
  }
115
210
  });
116
211
  }
117
- export function handleDeployment(targetPath, projectConfig) {
212
+ // STEP 1 prepare
213
+ // 1. check is template latest
214
+ // 2. input project name
215
+ // 3. choose framework or template
216
+ // 4. select a framework/template
217
+ // 5. TODO: js/ts
218
+ // STEP 2 init
219
+ // 1. execute framework init command
220
+ // 2. install esa-cli
221
+ // 3. config toml/jsonc
222
+ // STEP 3 customize
223
+ // 1. git yes/no
224
+ // 2. deploy yes/no
225
+ export function handleInit(argv) {
118
226
  return __awaiter(this, void 0, void 0, function* () {
119
- var _a, _b, _c;
120
- const isLoginSuccess = yield checkIsLoginSuccess();
121
- if (!isLoginSuccess) {
122
- logger.log(chalk.yellow(t('not_login_auto_deploy').d('You are not logged in, automatic deployment cannot be performed. Please log in later and manually deploy.')));
227
+ var _a, _b;
228
+ yield checkAndUpdatePackage('esa-template');
229
+ // Step 1 of 3: Planning selections (Cloudflare-like)
230
+ logger.cfStepHeader('Create an ESA application', 1, 3);
231
+ if (argv.config) {
232
+ const configFormat = yield promptConfigFormat(argv.yes);
233
+ yield generateConfigFile(undefined, undefined, undefined, configFormat);
234
+ exit(0);
235
+ }
236
+ // Update the template package (currently commented out)
237
+ // If config option is provided, generate config file and exit
238
+ const config = getCliConfig();
239
+ if (config === undefined) {
240
+ const configFormat = yield promptConfigFormat(argv.yes);
241
+ yield generateConfigFile(String(config), undefined, undefined, configFormat);
242
+ }
243
+ // Handle project name parameter
244
+ let name = argv.name;
245
+ if (!name) {
246
+ name = yield promptProjectName(argv.yes);
247
+ }
248
+ else {
249
+ if (!validateProjectName(name)) {
250
+ logger.error(t('init_name_error').d('Error: The project name must be at least 2 characters long and can only contain lowercase letters, numbers, and hyphens.'));
251
+ return;
252
+ }
253
+ }
254
+ // Show chosen directory
255
+ logger.cfStepItem('In which directory do you want to create your application?');
256
+ logger.cfStepKV('dir', `./${name}`);
257
+ logger.cfStepSpacer();
258
+ // Decide between framework or template if neither provided and not --yes
259
+ let framework = argv.framework;
260
+ let language = argv.language;
261
+ const allFrameworkConfig = getAllFrameworkConfig();
262
+ if (!framework && !argv.template && !argv.yes) {
263
+ const { initMode } = yield inquirer.prompt([
264
+ {
265
+ type: 'list',
266
+ name: 'initMode',
267
+ message: 'How would you like to initialize the project?',
268
+ prefix: '╰',
269
+ choices: [
270
+ { name: 'Use a framework (React/Vue/Next.js)', value: 'framework' },
271
+ {
272
+ name: 'Use ESA template (recommended for EdgeRoutine demos)',
273
+ value: 'template'
274
+ }
275
+ ]
276
+ }
277
+ ]);
278
+ logger.replacePrevLine('├ How would you like to initialize the project?');
279
+ logger.cfStepKV('category', initMode === 'framework' ? 'Framework Starter' : 'ESA Template');
280
+ logger.cfStepSpacer();
281
+ if (initMode === 'framework') {
282
+ const { fw } = yield inquirer.prompt([
283
+ {
284
+ type: 'list',
285
+ name: 'fw',
286
+ message: 'Select a framework',
287
+ prefix: '╰',
288
+ choices: Object.keys(allFrameworkConfig).map((fw) => ({
289
+ name: allFrameworkConfig[fw].label,
290
+ value: fw
291
+ }))
292
+ }
293
+ ]);
294
+ logger.replacePrevLine('├ Select a framework');
295
+ framework = fw;
296
+ logger.cfStepKV('framework', String(framework));
297
+ const frameworkConfig = getFrameworkConfig(framework);
298
+ if (frameworkConfig.templates) {
299
+ if (!language) {
300
+ language = yield promptLanguage(argv.yes);
301
+ }
302
+ logger.cfStepKV(t('init_language_selected').d('Language'), language);
303
+ }
304
+ logger.cfStepEnd('Configuration collected');
305
+ }
306
+ else if (initMode === 'template') {
307
+ // Use ESA Template creation method
308
+ const templateItems = prepareTemplateItems();
309
+ const selectedTemplatePath = yield selectTemplate(templateItems, argv.yes);
310
+ if (!selectedTemplatePath) {
311
+ return;
312
+ }
313
+ logger.cfStepEnd('Template selected');
314
+ // Step 2 of 3: Scaffold project
315
+ logger.cfStepHeader('Scaffold project', 2, 3);
316
+ const { template, targetPath } = (yield initializeProject(selectedTemplatePath, name)) || {};
317
+ if (!template || !targetPath) {
318
+ return;
319
+ }
320
+ logger.cfStepSpacer();
321
+ logger.cfStepEnd('Project initialized');
322
+ // Step 3 of 3: Configure and finalize
323
+ logger.cfStepHeader('Configure and finalize', 3, 3);
324
+ if (!argv.skip) {
325
+ yield handleGitInitialization(targetPath, argv.yes);
326
+ }
327
+ // Deployment prompt relies on config file just generated
328
+ if (!argv.skip) {
329
+ const projectConfig = getProjectConfig(targetPath);
330
+ if (projectConfig) {
331
+ yield initDeployment(targetPath, projectConfig, argv.yes, initMode);
332
+ }
333
+ }
334
+ logger.success('Project created successfully.');
335
+ return;
336
+ }
337
+ }
338
+ const frameworkConfig = getFrameworkConfig(framework || '');
339
+ if (framework) {
340
+ const targetPath = path.join(process.cwd(), name);
341
+ if (fs.existsSync(targetPath)) {
342
+ logger.error(t('already_exist_file_error').d('Error: The project already exists. It looks like a folder named "<project-name>" is already present in the current directory. Please try the following options: 1. Choose a different project name. 2. Delete the existing folder if it\'s not needed: `rm -rf <project-name>` (use with caution!). 3. Move to a different directory before running the init command.'));
343
+ return;
344
+ }
345
+ // Step 2 of 3: Scaffold project
346
+ logger.cfStepHeader('Scaffold project', 2, 3);
347
+ const command = frameworkConfig.command;
348
+ const templateFlag = ((_a = frameworkConfig.templates) === null || _a === void 0 ? void 0 : _a[language || 'typescript']) || '';
349
+ const fullCommand = `${command} ${name} ${templateFlag}`;
350
+ logger.cfStepItem(`Continue with ${framework} via \`${fullCommand}\``);
351
+ logger.cfStepKV('dir', `./${name}`);
352
+ logger.cfStepSpacer();
353
+ logger.log(`Creating ${framework} app in ${targetPath} ...`);
354
+ // Execute the command with proper arguments
355
+ if (templateFlag) {
356
+ execSync(`${command} ${name} ${templateFlag}`, {
357
+ stdio: 'inherit',
358
+ cwd: process.cwd()
359
+ });
360
+ }
361
+ else {
362
+ execSync(`${command} ${name}`, {
363
+ stdio: 'inherit',
364
+ cwd: process.cwd()
365
+ });
366
+ }
367
+ logger.cfStepSpacer();
368
+ // install dependencies
369
+ logger.cfStepItem('Install dependencies');
370
+ execSync('npm install', {
371
+ stdio: 'inherit',
372
+ cwd: targetPath
373
+ });
374
+ logger.cfStepSpacer();
375
+ // Post-process nextjs configuration for static export
376
+ if (framework === 'nextjs') {
377
+ logger.cfStepItem('Configuring Next.js for static export');
378
+ yield configureNextJsForStaticExport(targetPath);
379
+ logger.cfStepSpacer();
380
+ }
381
+ logger.cfStepEnd('Project initialized');
382
+ const assetsDirectory = (_b = frameworkConfig.assets) === null || _b === void 0 ? void 0 : _b.directory;
383
+ // Step 3 of 3: Configure and finalize
384
+ logger.cfStepHeader('Configure and finalize', 3, 3);
385
+ const configFormat = yield promptConfigFormat(argv.yes);
386
+ // logger.cfStepItem('Generate config file');
387
+ logger.cfStepKV('format', configFormat);
388
+ logger.cfStepSpacer();
389
+ yield generateConfigFile(name, {
390
+ assets: assetsDirectory ? { directory: assetsDirectory } : undefined
391
+ }, targetPath, configFormat);
392
+ if (!argv.skip) {
393
+ yield handleGitInitialization(targetPath, argv.yes);
394
+ }
395
+ // Deployment prompt relies on config file just generated
396
+ if (!argv.skip) {
397
+ const projectConfig = getProjectConfig(targetPath);
398
+ if (projectConfig) {
399
+ yield initDeployment(targetPath, projectConfig, argv.yes);
400
+ }
401
+ }
402
+ logger.success('Project created successfully.');
403
+ return;
404
+ }
405
+ });
406
+ }
407
+ export function initDeployment(targetPath_1, projectConfig_1) {
408
+ return __awaiter(this, arguments, void 0, function* (targetPath, projectConfig, yes = false, initMode = 'framework') {
409
+ if (yes) {
410
+ logger.log(`${t('auto_deploy').d('Do you want to deploy your project?')} Yes`);
411
+ yield quickDeployForInit(targetPath, projectConfig);
123
412
  return;
124
413
  }
125
414
  const { deploy } = yield inquirer.prompt([
@@ -127,49 +416,164 @@ export function handleDeployment(targetPath, projectConfig) {
127
416
  type: 'list',
128
417
  name: 'deploy',
129
418
  message: t('auto_deploy').d('Do you want to deploy your project?'),
419
+ prefix: '╰',
130
420
  choices: ['Yes', 'No']
131
421
  }
132
422
  ]);
423
+ logger.replacePrevLine('├ Do you want to deploy your project?');
133
424
  if (deploy === 'Yes') {
134
- yield checkRoutineExist((_a = projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.name) !== null && _a !== void 0 ? _a : '', targetPath);
135
- yield quickDeploy(targetPath, projectConfig);
136
- const service = yield ApiService.getInstance();
137
- const res = yield service.getRoutine({ Name: (_b = projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.name) !== null && _b !== void 0 ? _b : '' });
138
- const defaultUrl = (_c = res === null || res === void 0 ? void 0 : res.data) === null || _c === void 0 ? void 0 : _c.DefaultRelatedRecord;
139
- const visitUrl = defaultUrl ? 'http://' + defaultUrl : '';
140
- logger.success(`${t('init_deploy_success').d('Project deployment completed. Visit: ')}${chalk.yellowBright(visitUrl)}`);
141
- logger.warn(t('deploy_url_warn').d('The domain may take some time to take effect, please try again later.'));
425
+ if (initMode === 'framework') {
426
+ execSync('npm run build', { stdio: 'inherit', cwd: targetPath });
427
+ }
428
+ yield quickDeployForInit(targetPath, projectConfig);
142
429
  }
143
430
  });
144
431
  }
145
- export function handleInit(argv) {
432
+ function promptConfigFormat(yes) {
146
433
  return __awaiter(this, void 0, void 0, function* () {
147
- // Update the template package (currently commented out)
148
- yield checkAndUpdatePackage('esa-template');
149
- // If config option is provided, generate config file and exit
150
- const config = getCliConfig();
151
- if (config === undefined) {
152
- yield generateConfigFile(String(config));
434
+ if (yes) {
435
+ return 'jsonc';
153
436
  }
154
- const name = yield promptProjectName();
155
- const templateItems = prepareTemplateItems();
156
- // Select a template
157
- const selectedTemplatePath = yield selectTemplate(templateItems);
158
- if (!selectedTemplatePath) {
437
+ const { configFormat } = yield inquirer.prompt([
438
+ {
439
+ type: 'list',
440
+ name: 'configFormat',
441
+ message: t('init_config_format_select').d('Select configuration file format:'),
442
+ prefix: '╰',
443
+ choices: [
444
+ {
445
+ name: t('init_config_format_jsonc').d('JSONC (.jsonc) - JSON with comments, recommended'),
446
+ value: 'jsonc'
447
+ },
448
+ {
449
+ name: t('init_config_format_toml').d('TOML (.toml) - Traditional format'),
450
+ value: 'toml'
451
+ }
452
+ ],
453
+ default: 'jsonc'
454
+ }
455
+ ]);
456
+ logger.replacePrevLine('├ Select configuration file format:');
457
+ return configFormat;
458
+ });
459
+ }
460
+ function promptLanguage(yes) {
461
+ return __awaiter(this, void 0, void 0, function* () {
462
+ if (yes) {
463
+ return 'typescript';
464
+ }
465
+ const { language } = yield inquirer.prompt([
466
+ {
467
+ type: 'list',
468
+ name: 'language',
469
+ message: t('init_language_select').d('Select programming language:'),
470
+ prefix: '╰',
471
+ choices: [
472
+ {
473
+ name: t('init_language_typescript').d('TypeScript (.ts) - Type-safe JavaScript, recommended'),
474
+ value: 'typescript'
475
+ },
476
+ {
477
+ name: t('init_language_javascript').d('JavaScript (.js) - Traditional JavaScript'),
478
+ value: 'javascript'
479
+ }
480
+ ],
481
+ default: 'typescript'
482
+ }
483
+ ]);
484
+ logger.replacePrevLine('├ Select programming language:');
485
+ return language;
486
+ });
487
+ }
488
+ /**
489
+ * Configure Next.js for static export by modifying next.config.ts/js
490
+ * @param targetPath Path to the Next.js project
491
+ */
492
+ export function configureNextJsForStaticExport(targetPath) {
493
+ return __awaiter(this, void 0, void 0, function* () {
494
+ const nextConfigTsPath = path.join(targetPath, 'next.config.ts');
495
+ const nextConfigJsPath = path.join(targetPath, 'next.config.js');
496
+ const nextConfigMjsPath = path.join(targetPath, 'next.config.mjs');
497
+ let configPath = null;
498
+ let configContent = '';
499
+ // Check which config file exists
500
+ if (fs.existsSync(nextConfigTsPath)) {
501
+ configPath = nextConfigTsPath;
502
+ configContent = fs.readFileSync(nextConfigTsPath, 'utf-8');
503
+ }
504
+ else if (fs.existsSync(nextConfigJsPath)) {
505
+ configPath = nextConfigJsPath;
506
+ configContent = fs.readFileSync(nextConfigJsPath, 'utf-8');
507
+ }
508
+ else if (fs.existsSync(nextConfigMjsPath)) {
509
+ configPath = nextConfigMjsPath;
510
+ configContent = fs.readFileSync(nextConfigMjsPath, 'utf-8');
511
+ }
512
+ if (!configPath) {
513
+ // Create a new next.config.ts file if none exists
514
+ configPath = nextConfigTsPath;
515
+ const newConfig = `import type { NextConfig } from "next";
516
+
517
+ const nextConfig: NextConfig = {
518
+ output: "export",
519
+ trailingSlash: true,
520
+ images: {
521
+ unoptimized: true
522
+ }
523
+ };
524
+
525
+ export default nextConfig;`;
526
+ fs.writeFileSync(configPath, newConfig, 'utf-8');
527
+ logger.success('Created next.config.ts with static export configuration');
159
528
  return;
160
529
  }
161
- // Initialize project files and configuration
162
- const project = yield initializeProject(selectedTemplatePath, name);
163
- if (!project) {
530
+ // Check if output: 'export' is already configured
531
+ if (configContent.includes('output: "export"') || configContent.includes("output: 'export'")) {
532
+ logger.success('Next.js is already configured for static export');
164
533
  return;
165
534
  }
166
- const { template, targetPath } = project;
167
- // Handle Git initialization
168
- yield handleGitInitialization(targetPath);
169
- // Handle deployment
170
- const projectConfig = getProjectConfig(targetPath);
171
- yield handleDeployment(targetPath, projectConfig);
172
- template.printSummary();
173
- return;
535
+ // Modify existing config to add output: 'export'
536
+ let modifiedContent = configContent;
537
+ // Handle different config formats
538
+ if (configPath.endsWith('.ts')) {
539
+ // TypeScript config
540
+ if (configContent.includes('const nextConfig = {')) {
541
+ // Add output: 'export' after the opening brace
542
+ modifiedContent = configContent.replace(/(const nextConfig\s*=\s*\{)/, `$1
543
+ output: "export",`);
544
+ }
545
+ else if (configContent.includes('export default {')) {
546
+ // Add output: 'export' after the opening brace
547
+ modifiedContent = configContent.replace(/(export default\s*\{)/, `$1
548
+ output: "export",`);
549
+ }
550
+ }
551
+ else {
552
+ // JavaScript config
553
+ if (configContent.includes('const nextConfig = {')) {
554
+ // Add output: 'export' after the opening brace
555
+ modifiedContent = configContent.replace(/(const nextConfig\s*=\s*\{)/, `$1
556
+ output: "export",`);
557
+ }
558
+ else if (configContent.includes('module.exports = {')) {
559
+ // Add output: 'export' after the opening brace
560
+ modifiedContent = configContent.replace(/(module\.exports\s*=\s*\{)/, `$1
561
+ output: "export",`);
562
+ }
563
+ }
564
+ // Add trailingSlash and images configuration if not present
565
+ if (!modifiedContent.includes('trailingSlash')) {
566
+ modifiedContent = modifiedContent.replace(/(output: "export",)/, `$1
567
+ trailingSlash: true,`);
568
+ }
569
+ if (!modifiedContent.includes('images')) {
570
+ modifiedContent = modifiedContent.replace(/(trailingSlash: true,)/, `$1
571
+ images: {
572
+ unoptimized: true
573
+ }`);
574
+ }
575
+ // Write the modified config back to file
576
+ fs.writeFileSync(configPath, modifiedContent, 'utf-8');
577
+ logger.success('Next.js configured for static export successfully');
174
578
  });
175
579
  }
@@ -0,0 +1,34 @@
1
+ {
2
+ "react": {
3
+ "label": "React",
4
+ "command": "npm create vite@latest",
5
+ "templates": {
6
+ "typescript": "-- --template react-ts",
7
+ "javascript": "-- --template react"
8
+ },
9
+ "assets": {
10
+ "directory": "./dist",
11
+ "notFoundStrategy": "singlePageApplication"
12
+ }
13
+ },
14
+ "vue": {
15
+ "label": "Vue",
16
+ "command": "npm create vite@latest",
17
+ "templates": {
18
+ "typescript": "-- --template vue-ts -- --use-npm",
19
+ "javascript": "-- --template vue"
20
+ },
21
+ "assets": {
22
+ "directory": "./dist",
23
+ "notFoundStrategy": "singlePageApplication"
24
+ }
25
+ },
26
+ "nextjs": {
27
+ "label": "Next.js",
28
+ "command": "npx create-next-app@latest",
29
+ "assets": {
30
+ "directory": "./out",
31
+ "notFoundStrategy": "singlePageApplication"
32
+ }
33
+ }
34
+ }
@@ -8,9 +8,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import SelectItems from '../components/selectInput.js';
11
- import { updateCliConfigFile } from '../utils/fileUtils/index.js';
12
- import logger from '../libs/logger.js';
13
11
  import t from '../i18n/index.js';
12
+ import logger from '../libs/logger.js';
13
+ import { updateCliConfigFile } from '../utils/fileUtils/index.js';
14
14
  const docs = {
15
15
  command: 'lang',
16
16
  describe: `🌐 ${t('lang_describe').d('Set the language of the CLI')}`,