esa-cli 0.0.5 → 1.0.1

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 (85) hide show
  1. package/README.md +34 -145
  2. package/dist/commands/commit/index.js +49 -104
  3. package/dist/commands/commit/prodBuild.js +2 -3
  4. package/dist/commands/common/constant.js +4 -4
  5. package/dist/commands/common/utils.js +419 -0
  6. package/dist/commands/config.js +2 -2
  7. package/dist/commands/deploy/helper.js +43 -49
  8. package/dist/commands/deploy/index.js +51 -174
  9. package/dist/commands/deployments/delete.js +32 -22
  10. package/dist/commands/deployments/index.js +4 -4
  11. package/dist/commands/deployments/list.js +21 -34
  12. package/dist/commands/dev/build.js +3 -3
  13. package/dist/commands/dev/doProcess.js +5 -5
  14. package/dist/commands/dev/ew2/cacheService.js +33 -0
  15. package/dist/commands/dev/ew2/devEntry.js +2 -1
  16. package/dist/commands/dev/ew2/devPack.js +31 -20
  17. package/dist/commands/dev/ew2/kvService.js +50 -0
  18. package/dist/commands/dev/ew2/mock/cache.js +99 -15
  19. package/dist/commands/dev/ew2/mock/kv.js +142 -21
  20. package/dist/commands/dev/ew2/server.js +163 -28
  21. package/dist/commands/dev/index.js +17 -18
  22. package/dist/commands/dev/mockWorker/devPack.js +19 -10
  23. package/dist/commands/dev/mockWorker/server.js +7 -6
  24. package/dist/commands/domain/add.js +4 -4
  25. package/dist/commands/domain/delete.js +3 -3
  26. package/dist/commands/domain/index.js +4 -4
  27. package/dist/commands/domain/list.js +7 -7
  28. package/dist/commands/init/helper.js +654 -21
  29. package/dist/commands/init/index.js +88 -152
  30. package/dist/commands/init/snippets/nextjs/next.config.mjs +6 -0
  31. package/dist/commands/init/snippets/nextjs/next.config.ts +7 -0
  32. package/dist/commands/init/snippets/react-router/react-router.config.ts +7 -0
  33. package/dist/commands/init/template.jsonc +84 -0
  34. package/dist/commands/init/types.js +1 -0
  35. package/dist/commands/lang.js +2 -2
  36. package/dist/commands/login/index.js +74 -34
  37. package/dist/commands/logout.js +6 -6
  38. package/dist/commands/route/add.js +101 -43
  39. package/dist/commands/route/delete.js +6 -6
  40. package/dist/commands/route/helper.js +9 -10
  41. package/dist/commands/route/index.js +4 -4
  42. package/dist/commands/route/list.js +4 -4
  43. package/dist/commands/routine/delete.js +9 -8
  44. package/dist/commands/routine/index.js +6 -5
  45. package/dist/commands/routine/list.js +45 -39
  46. package/dist/commands/site/index.js +3 -3
  47. package/dist/commands/site/list.js +6 -7
  48. package/dist/commands/utils.js +61 -25
  49. package/dist/components/descriptionInput.js +1 -1
  50. package/dist/components/filterSelector.js +1 -1
  51. package/dist/components/mutiLevelSelect.js +19 -20
  52. package/dist/components/mutiSelectTable.js +1 -1
  53. package/dist/components/routeBuilder.js +68 -0
  54. package/dist/components/selectInput.js +2 -3
  55. package/dist/components/selectItem.js +1 -1
  56. package/dist/docs/Commands_en.md +164 -117
  57. package/dist/docs/Commands_zh_CN.md +155 -107
  58. package/dist/docs/Config_en.md +70 -0
  59. package/dist/docs/Config_zh_CN.md +68 -0
  60. package/dist/i18n/index.js +2 -2
  61. package/dist/i18n/locales.json +418 -82
  62. package/dist/index.js +28 -13
  63. package/dist/libs/api.js +3 -6
  64. package/dist/libs/apiService.js +201 -70
  65. package/dist/libs/git/index.js +86 -9
  66. package/dist/libs/interface.js +0 -1
  67. package/dist/libs/logger.js +162 -10
  68. package/dist/libs/service.js +2 -2
  69. package/dist/libs/templates/index.js +1 -1
  70. package/dist/utils/checkAssetsExist.js +80 -0
  71. package/dist/utils/checkDevPort.js +5 -19
  72. package/dist/utils/checkEntryFileExist.js +10 -0
  73. package/dist/utils/checkIsRoutineCreated.js +27 -21
  74. package/dist/utils/checkVersion.js +119 -1
  75. package/dist/utils/command.js +149 -0
  76. package/dist/utils/compress.js +142 -0
  77. package/dist/utils/download.js +8 -8
  78. package/dist/utils/fileMd5.js +1 -1
  79. package/dist/utils/fileUtils/index.js +136 -45
  80. package/dist/utils/installDeno.js +4 -4
  81. package/dist/utils/installEw2.js +9 -9
  82. package/dist/utils/openInBrowser.js +1 -1
  83. package/dist/utils/prompt.js +97 -0
  84. package/package.json +23 -12
  85. package/zh_CN.md +31 -150
@@ -0,0 +1,149 @@
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 { spawn } from 'child_process';
11
+ import { cancel, spinner } from '@clack/prompts';
12
+ import chalk from 'chalk';
13
+ /**
14
+ * Execute a shell command with rich options (spinner, capture, env, cwd).
15
+ */
16
+ export const execCommand = (command_1, ...args_1) => __awaiter(void 0, [command_1, ...args_1], void 0, function* (command, options = {}) {
17
+ const { startText, doneText, silent = false, captureOutput = false, useSpinner = true, realtimeOutput = false, interactive = false, env, cwd, transformOutput, fallbackOutput, errorMessage } = options;
18
+ // Determine stdio mode based on options
19
+ // If realtimeOutput is true, we need to pipe to capture and display output in real-time
20
+ // If spinner is used without realtimeOutput, pipe to avoid TTY contention
21
+ // If silent is true, pipe to suppress output
22
+ // If captureOutput is true, pipe to capture output
23
+ // If interactive is true, always inherit stdio so prompts can be shown and accept input
24
+ const shouldPipe = !interactive && (realtimeOutput || useSpinner || silent || captureOutput);
25
+ const stdio = interactive
26
+ ? 'inherit'
27
+ : shouldPipe
28
+ ? 'pipe'
29
+ : 'inherit';
30
+ // start
31
+ const startMsg = startText || `Running: ${command.join(' ')}`;
32
+ const s = spinner();
33
+ // When realtimeOutput is enabled, don't use spinner as it conflicts with real-time output
34
+ if (useSpinner && !realtimeOutput && !interactive) {
35
+ s.start(startMsg);
36
+ }
37
+ else if (!silent) {
38
+ if (interactive) {
39
+ console.log(chalk.gray('│'));
40
+ console.log(chalk.gray('├ ') + startMsg);
41
+ }
42
+ else {
43
+ console.log(startMsg);
44
+ }
45
+ }
46
+ try {
47
+ let stdout = '';
48
+ let stderr = '';
49
+ // Use spawn for string[] commands to avoid shell quoting issues
50
+ const program = command[0];
51
+ const args = command.slice(1);
52
+ yield new Promise((resolve, reject) => {
53
+ var _a, _b;
54
+ const child = spawn(program, args, {
55
+ stdio,
56
+ cwd,
57
+ env: Object.assign(Object.assign({}, process.env), env),
58
+ shell: false
59
+ });
60
+ if (stdio === 'pipe') {
61
+ (_a = child.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (chunk) => {
62
+ const chunkStr = String(chunk);
63
+ stdout += chunkStr;
64
+ // Real-time output: display immediately if enabled and not silent
65
+ if (realtimeOutput && !silent) {
66
+ process.stdout.write(chunkStr);
67
+ }
68
+ });
69
+ (_b = child.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (chunk) => {
70
+ const chunkStr = String(chunk);
71
+ stderr += chunkStr;
72
+ // Real-time output: display immediately if enabled and not silent
73
+ if (realtimeOutput && !silent) {
74
+ process.stderr.write(chunkStr);
75
+ }
76
+ });
77
+ }
78
+ child.on('error', (error) => {
79
+ reject(error);
80
+ });
81
+ child.on('close', (code) => {
82
+ if (code && code !== 0) {
83
+ reject({ stdout, stderr, message: `Exit code ${code}` });
84
+ }
85
+ else {
86
+ resolve();
87
+ }
88
+ });
89
+ });
90
+ // Preserve original output for optional mirroring
91
+ const bufferedStdout = stdout;
92
+ const bufferedStderr = stderr;
93
+ if (transformOutput) {
94
+ stdout = transformOutput(stdout);
95
+ }
96
+ const endMsg = typeof doneText === 'function' ? doneText(stdout) : doneText || 'Done';
97
+ if (useSpinner && !realtimeOutput && !interactive) {
98
+ s.stop(endMsg);
99
+ }
100
+ else if (!silent) {
101
+ if (interactive) {
102
+ console.log(chalk.gray('├ ') + endMsg);
103
+ }
104
+ else {
105
+ console.log(endMsg);
106
+ }
107
+ }
108
+ // If spinner was used and user expects output (silent=false, captureOutput=false),
109
+ // and realtimeOutput is not enabled, print the buffered child output now to avoid interfering with spinner rendering.
110
+ if (useSpinner &&
111
+ !silent &&
112
+ !captureOutput &&
113
+ !realtimeOutput &&
114
+ !interactive) {
115
+ if (bufferedStdout)
116
+ process.stdout.write(bufferedStdout);
117
+ if (bufferedStderr)
118
+ process.stderr.write(bufferedStderr);
119
+ }
120
+ return { success: true, stdout, stderr };
121
+ }
122
+ catch (err) {
123
+ const e = err;
124
+ const stdout = (e === null || e === void 0 ? void 0 : e.stdout) ? String(e.stdout) : '';
125
+ const stderr = (e === null || e === void 0 ? void 0 : e.stderr) ? String(e.stderr) : (e === null || e === void 0 ? void 0 : e.message) || '';
126
+ const msg = (fallbackOutput && fallbackOutput(err)) ||
127
+ (stderr ? `Command failed: ${stdout}` : 'Command failed');
128
+ if (useSpinner && !realtimeOutput && !interactive)
129
+ s.stop(msg);
130
+ else if (!silent)
131
+ console.error(msg);
132
+ // Mirror buffered outputs on failure when spinner is used and not silent and realtimeOutput is not enabled
133
+ if (useSpinner &&
134
+ !silent &&
135
+ !captureOutput &&
136
+ !realtimeOutput &&
137
+ !interactive) {
138
+ if (stdout)
139
+ process.stdout.write(stdout);
140
+ if (stderr)
141
+ process.stderr.write(stderr);
142
+ }
143
+ if (errorMessage) {
144
+ cancel(errorMessage);
145
+ }
146
+ return { success: false, stdout, stderr };
147
+ }
148
+ });
149
+ export default execCommand;
@@ -0,0 +1,142 @@
1
+ /*
2
+ Toml Example:
3
+ name = "DeepSeek model invocation"
4
+ description = 'How to invoke DeepSeek series models through API calls on the BaiLian platform.'
5
+ entry = "src/index.js"
6
+ assets = ["src/assets"]
7
+ codeVersions = [ ]
8
+
9
+ [assets]
10
+ directory = './assets/'
11
+
12
+ [dev]
13
+ port = 18080
14
+ localUpstream = ''
15
+ */
16
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
17
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
18
+ return new (P || (P = Promise))(function (resolve, reject) {
19
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
20
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
21
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
22
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
23
+ });
24
+ };
25
+ import fs from 'fs';
26
+ import path from 'path';
27
+ import { exit } from 'process';
28
+ import AdmZip from 'adm-zip';
29
+ import chalk from 'chalk';
30
+ import prodBuild from '../commands/commit/prodBuild.js';
31
+ import t from '../i18n/index.js';
32
+ import logger from '../libs/logger.js';
33
+ import { checkEdgeRoutineType, EDGE_ROUTINE_TYPE } from './checkAssetsExist.js';
34
+ import { getProjectConfig, readEdgeRoutineFile } from './fileUtils/index.js';
35
+ const compress = (scriptEntry_1, assetsDir_1, ...args_1) => __awaiter(void 0, [scriptEntry_1, assetsDir_1, ...args_1], void 0, function* (scriptEntry, assetsDir, minify = false, projectPath) {
36
+ var _a;
37
+ let code;
38
+ const zip = new AdmZip();
39
+ const fileList = [];
40
+ const sourceList = [];
41
+ const dynamicSources = [];
42
+ const projectConfig = getProjectConfig(projectPath);
43
+ let assetsDirectory = assetsDir || ((_a = projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.assets) === null || _a === void 0 ? void 0 : _a.directory);
44
+ const routineType = checkEdgeRoutineType(scriptEntry, assetsDir, projectPath);
45
+ if (!projectConfig && !scriptEntry && !assetsDir) {
46
+ logger.error([
47
+ 'esa.jsonc (recommended) or esa.toml is not found and script entry or assets directory is not provided by command line',
48
+ '',
49
+ 'See configuration guide:',
50
+ `- English: ${chalk.underline('https://github.com/aliyun/alibabacloud-esa-cli/blob/main/docs/Config_en.md')}`,
51
+ `- 中文: ${chalk.underline('https://github.com/aliyun/alibabacloud-esa-cli/blob/main/docs/Config_zh_CN.md')}`
52
+ ].join('\n'));
53
+ exit(1);
54
+ }
55
+ // Parameter priority: use parameters if available, otherwise use values from config file
56
+ const entry = scriptEntry || (projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.entry);
57
+ if (routineType === EDGE_ROUTINE_TYPE.NOT_EXIST) {
58
+ const errorMessage = [
59
+ chalk.red.bold('❌ File upload failed'),
60
+ '',
61
+ chalk.cyan('📋 Current configuration information:'),
62
+ `${chalk.white(` 📄 Entry file ${chalk.yellow('(dynamic)')} :`)} ${chalk.yellow(scriptEntry ||
63
+ (projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.entry) ||
64
+ chalk.gray(t('compress_not_configured').d('Not configured')))}`,
65
+ `${chalk.white(` 🗂️ Assets directory ${chalk.yellow('(static)')} :`)} ${chalk.yellow(assetsDirectory || chalk.gray(t('compress_not_configured').d('Not configured')))}`,
66
+ '',
67
+ chalk.cyan('🔍 Possible issue causes:'),
68
+ chalk.white(' 1. Entry file path is incorrect or file does not exist'),
69
+ chalk.white(' 2. Assets directory path is incorrect or directory does not exist'),
70
+ chalk.white(` 3. Project configuration file ${chalk.yellow('esa.jsonc')} (recommended) or ${chalk.yellow('esa.toml')} format error`),
71
+ chalk.white(` 4. Relative path format error, please use ${chalk.yellow('./xxx')} format`),
72
+ '',
73
+ chalk.yellow.bold(`📍 Please check if the following ${chalk.red('absolute paths')} are correct:`),
74
+ ...(scriptEntry || (projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.entry)
75
+ ? [
76
+ `${chalk.white(' 📄 Entry file:')} ${chalk.cyan.bold(path.resolve(projectPath !== null && projectPath !== void 0 ? projectPath : '', scriptEntry || (projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.entry) || ''))} ${chalk.gray(t('compress_check_file_exists').d('(Check if file exists)'))}`
77
+ ]
78
+ : []),
79
+ ...(assetsDirectory
80
+ ? [
81
+ `${chalk.white(' 🗂️ Assets directory:')} ${chalk.cyan.bold(path.resolve(projectPath !== null && projectPath !== void 0 ? projectPath : '', assetsDirectory))} ${chalk.gray(t('compress_check_directory_exists').d('(Check if directory exists)'))}`
82
+ ]
83
+ : []),
84
+ ...(!scriptEntry && !(projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.entry) && !assetsDirectory
85
+ ? [
86
+ chalk.yellow.bold(' ⚠️ You need to configure at least one of entry file or assets directory')
87
+ ]
88
+ : []),
89
+ ''
90
+ ].join('\n');
91
+ logger.error(errorMessage);
92
+ exit(1);
93
+ }
94
+ if (routineType === EDGE_ROUTINE_TYPE.JS_ONLY ||
95
+ routineType === EDGE_ROUTINE_TYPE.JS_AND_ASSETS) {
96
+ const buildEntry = path.resolve(projectPath !== null && projectPath !== void 0 ? projectPath : '', entry !== null && entry !== void 0 ? entry : '');
97
+ yield prodBuild(minify, buildEntry, projectPath);
98
+ code = readEdgeRoutineFile(projectPath);
99
+ zip.addFile(`routine/index.js`, Buffer.from(code || ''));
100
+ fileList.push('routine/index.js');
101
+ const relativeEntry = path
102
+ .relative(projectPath !== null && projectPath !== void 0 ? projectPath : '', buildEntry)
103
+ .split(path.sep)
104
+ .join('/');
105
+ sourceList.push(relativeEntry);
106
+ dynamicSources.push(relativeEntry);
107
+ }
108
+ assetsDirectory = path.resolve(projectPath !== null && projectPath !== void 0 ? projectPath : '', assetsDirectory !== null && assetsDirectory !== void 0 ? assetsDirectory : '');
109
+ // Add all files in the assets directory to the /assets directory
110
+ if ((routineType === EDGE_ROUTINE_TYPE.JS_AND_ASSETS ||
111
+ routineType === EDGE_ROUTINE_TYPE.ASSETS_ONLY) &&
112
+ assetsDirectory &&
113
+ fs.existsSync(assetsDirectory)) {
114
+ const addDirectoryToZip = (dirPath, zipPath) => {
115
+ const files = fs.readdirSync(dirPath);
116
+ for (const file of files) {
117
+ const fullPath = path.join(dirPath, file);
118
+ const stat = fs.statSync(fullPath);
119
+ if (stat.isDirectory()) {
120
+ addDirectoryToZip(fullPath, path.join(zipPath, file));
121
+ }
122
+ else {
123
+ const fileContent = fs.readFileSync(fullPath);
124
+ const relativePath = path
125
+ .relative(assetsDirectory, fullPath)
126
+ .split(path.sep)
127
+ .join('/');
128
+ zip.addFile(`assets/${relativePath}`, fileContent);
129
+ fileList.push(`assets/${relativePath}`);
130
+ const relativeSrcPath = path
131
+ .relative(projectPath !== null && projectPath !== void 0 ? projectPath : '', fullPath)
132
+ .split(path.sep)
133
+ .join('/');
134
+ sourceList.push(relativeSrcPath);
135
+ }
136
+ }
137
+ };
138
+ addDirectoryToZip(assetsDirectory, 'assets');
139
+ }
140
+ return { zip, fileList, sourceList, dynamicSources };
141
+ });
142
+ export default compress;
@@ -7,16 +7,16 @@ 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 fetch from 'node-fetch';
10
+ import { exec } from 'child_process';
11
11
  import * as fs from 'fs/promises';
12
- import * as path from 'path';
13
12
  import os from 'os';
14
- import AdmZip from 'adm-zip';
15
- import { exec } from 'child_process';
13
+ import * as path from 'path';
16
14
  import { promisify } from 'util';
15
+ import AdmZip from 'adm-zip';
16
+ import chalk from 'chalk';
17
+ import fetch from 'node-fetch';
17
18
  import t from '../i18n/index.js';
18
19
  import logger from '../libs/logger.js';
19
- import chalk from 'chalk';
20
20
  const execAsync = promisify(exec);
21
21
  function getBinDir() {
22
22
  const home = os.homedir();
@@ -92,8 +92,8 @@ function isBinDirInPath(binDir) {
92
92
  */
93
93
  function addBinDirToPath(binDir) {
94
94
  return __awaiter(this, void 0, void 0, function* () {
95
- // 使用 setx 添加到 PATH
96
- // setx PATH 的长度有2047字符的限制
95
+ // Use setx to add to PATH
96
+ // setx has a 2047 character limit for PATH
97
97
  const command = `setx Path "%Path%;${binDir}"`;
98
98
  try {
99
99
  yield execAsync(command);
@@ -169,7 +169,7 @@ export function downloadRuntimeAndUnzipForWindows() {
169
169
  }
170
170
  logger.success(t('deno_install_success').d('Runtime install success!'));
171
171
  logger.block();
172
- const dev = chalk.green('esa dev');
172
+ const dev = chalk.green('esa-cli dev');
173
173
  logger.log(t('deno_install_success_tips', { dev }).d(`Please run ${dev} again`));
174
174
  }
175
175
  catch (error) {
@@ -1,5 +1,5 @@
1
- import fs from 'fs-extra';
2
1
  import crypto from 'crypto';
2
+ import fs from 'fs-extra';
3
3
  export function calculateFileMD5(filePath) {
4
4
  return new Promise((resolve, reject) => {
5
5
  const hash = crypto.createHash('md5');
@@ -7,19 +7,40 @@ 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';
10
+ import fs, { promises as fsPromises } from 'fs';
11
11
  import os from 'os';
12
12
  import path from 'path';
13
13
  import toml from '@iarna/toml';
14
- import { promises as fsPromises } from 'fs';
15
- import { getDirName, getRoot } from './base.js';
16
- import logger from '../../libs/logger.js';
17
14
  import t from '../../i18n/index.js';
18
- const projectConfigFile = 'esa.toml';
15
+ import logger from '../../libs/logger.js';
16
+ import { getDirName, getRoot } from './base.js';
19
17
  const __dirname = getDirName(import.meta.url);
20
18
  const root = getRoot();
21
- export const projectConfigPath = path.join(root, projectConfigFile);
19
+ // Function to get the actual project config file path (supports both .jsonc and .toml)
20
+ export const getProjectConfigPath = (filePath = root) => {
21
+ const configFormats = ['esa.jsonc', 'esa.toml'];
22
+ for (const format of configFormats) {
23
+ const configPath = path.join(filePath, format);
24
+ if (fs.existsSync(configPath)) {
25
+ return configPath;
26
+ }
27
+ }
28
+ // Default to .jsonc if no config file exists
29
+ return path.join(filePath, 'esa.jsonc');
30
+ };
31
+ export const projectConfigPath = getProjectConfigPath();
22
32
  export const cliConfigPath = path.join(os.homedir(), '.esa/config/default.toml');
33
+ // Function to get the actual config file path (supports both .toml and .jsonc)
34
+ export const getCliConfigPath = () => {
35
+ const configDir = path.join(os.homedir(), '.esa/config');
36
+ const jsoncPath = path.join(configDir, 'default.jsonc');
37
+ const tomlPath = path.join(configDir, 'default.toml');
38
+ // Check if JSONC file exists first, then fallback to TOML
39
+ if (fs.existsSync(jsoncPath)) {
40
+ return jsoncPath;
41
+ }
42
+ return tomlPath;
43
+ };
23
44
  export const hiddenConfigDir = path.join(os.homedir(), '.esa/config');
24
45
  export const generateHiddenConfigDir = () => {
25
46
  if (!fs.existsSync(hiddenConfigDir)) {
@@ -29,7 +50,7 @@ export const generateHiddenConfigDir = () => {
29
50
  export const generateToml = (path) => {
30
51
  if (!fs.existsSync(path)) {
31
52
  fs.writeFileSync(path, '', 'utf-8');
32
- // 添加默认的endpoint
53
+ // Add default endpoint
33
54
  const defaultConfig = {
34
55
  endpoint: 'esa.cn-hangzhou.aliyuncs.com'
35
56
  };
@@ -38,20 +59,34 @@ export const generateToml = (path) => {
38
59
  };
39
60
  export const generateDefaultConfig = () => {
40
61
  generateHiddenConfigDir();
41
- generateToml(cliConfigPath);
62
+ const configPath = getCliConfigPath();
63
+ generateToml(configPath);
42
64
  };
43
65
  export function updateProjectConfigFile(configUpdate_1) {
44
66
  return __awaiter(this, arguments, void 0, function* (configUpdate, filePath = root) {
45
- const configPath = path.join(filePath, projectConfigFile);
67
+ const configPath = getProjectConfigPath(filePath);
46
68
  try {
47
69
  let configFileContent = yield fsPromises.readFile(configPath, 'utf8');
48
- let config = toml.parse(configFileContent);
49
- config = Object.assign(Object.assign({}, config), configUpdate);
50
- const updatedConfigString = toml.stringify(config);
70
+ let config;
71
+ let updatedConfigString;
72
+ // Detect file format based on file extension
73
+ if (configPath.endsWith('.jsonc') || configPath.endsWith('.json')) {
74
+ // Handle JSONC format
75
+ const jsonContent = configFileContent.replace(/\/\*[\s\S]*?\*\/|\/\/.*$/gm, '');
76
+ config = JSON.parse(jsonContent);
77
+ config = Object.assign(Object.assign({}, config), configUpdate);
78
+ updatedConfigString = JSON.stringify(config, null, 2) + '\n';
79
+ }
80
+ else {
81
+ // Handle TOML format (default)
82
+ config = toml.parse(configFileContent);
83
+ config = Object.assign(Object.assign({}, config), configUpdate);
84
+ updatedConfigString = toml.stringify(config);
85
+ }
51
86
  yield fsPromises.writeFile(configPath, updatedConfigString);
52
87
  }
53
88
  catch (error) {
54
- logger.error(`Error updating TOML file: ${error}`);
89
+ logger.error(`Error updating config file: ${error}`);
55
90
  logger.pathEacces(__dirname);
56
91
  }
57
92
  });
@@ -59,16 +94,30 @@ export function updateProjectConfigFile(configUpdate_1) {
59
94
  export function updateCliConfigFile(configUpdate) {
60
95
  return __awaiter(this, void 0, void 0, function* () {
61
96
  try {
62
- let configFileContent = yield fsPromises.readFile(cliConfigPath, 'utf8');
63
- let config = toml.parse(configFileContent);
64
- config = Object.assign(Object.assign({}, config), configUpdate);
65
- const updatedConfigString = toml.stringify(config);
66
- yield fsPromises.writeFile(cliConfigPath, updatedConfigString);
97
+ const configPath = getCliConfigPath();
98
+ let configFileContent = yield fsPromises.readFile(configPath, 'utf8');
99
+ let config;
100
+ let updatedConfigString;
101
+ // Detect file format based on file extension
102
+ if (configPath.endsWith('.jsonc') || configPath.endsWith('.json')) {
103
+ // Handle JSONC format
104
+ const jsonContent = configFileContent.replace(/\/\*[\s\S]*?\*\/|\/\/.*$/gm, '');
105
+ config = JSON.parse(jsonContent);
106
+ config = Object.assign(Object.assign({}, config), configUpdate);
107
+ updatedConfigString = JSON.stringify(config, null, 2) + '\n';
108
+ }
109
+ else {
110
+ // Handle TOML format (default)
111
+ config = toml.parse(configFileContent);
112
+ config = Object.assign(Object.assign({}, config), configUpdate);
113
+ updatedConfigString = toml.stringify(config);
114
+ }
115
+ yield fsPromises.writeFile(configPath, updatedConfigString);
67
116
  }
68
117
  catch (error) {
69
- logger.error(`Error updating TOML file: ${error}`);
118
+ logger.error(`Error updating config file: ${error}`);
70
119
  logger.pathEacces(__dirname);
71
- throw new Error('Login error');
120
+ throw new Error('Config update error');
72
121
  }
73
122
  });
74
123
  }
@@ -76,35 +125,46 @@ export function readConfigFile(configPath) {
76
125
  if (fs.existsSync(configPath)) {
77
126
  const configFileContent = fs.readFileSync(configPath, 'utf-8');
78
127
  try {
79
- const config = toml.parse(configFileContent);
80
- return config;
128
+ if (configPath.endsWith('.jsonc') || configPath.endsWith('.json')) {
129
+ // Remove comments for JSON parsing
130
+ const jsonContent = configFileContent.replace(/\/\*[\s\S]*?\*\/|\/\/.*$/gm, '');
131
+ const config = JSON.parse(jsonContent);
132
+ return config;
133
+ }
134
+ else {
135
+ // TOML format
136
+ const config = toml.parse(configFileContent);
137
+ return config;
138
+ }
81
139
  }
82
140
  catch (error) {
83
- logger.error(`Error parsing TOML file: ${error}`);
141
+ logger.error(`Error parsing config file: ${error}`);
84
142
  return null;
85
143
  }
86
144
  }
87
145
  return null;
88
146
  }
89
147
  export function getCliConfig() {
90
- const res = readConfigFile(cliConfigPath);
148
+ const configPath = getCliConfigPath();
149
+ const res = readConfigFile(configPath);
91
150
  if (!res) {
92
151
  return null;
93
152
  }
94
153
  return res;
95
154
  }
96
155
  export function getProjectConfig(filePath = root) {
97
- const res = readConfigFile(path.join(filePath, projectConfigFile));
98
- if (!res) {
99
- return null;
156
+ // Try to find config file in order of preference: .jsonc, .toml
157
+ const configFormats = ['esa.jsonc', 'esa.toml'];
158
+ for (const format of configFormats) {
159
+ const configPath = path.join(filePath, format);
160
+ const config = readConfigFile(configPath);
161
+ if (config) {
162
+ return config;
163
+ }
100
164
  }
101
- return res;
165
+ return null;
102
166
  }
103
167
  export function readEdgeRoutineFile(projectPath = root) {
104
- const projectConfig = getProjectConfig(projectPath);
105
- if (!projectConfig) {
106
- return null;
107
- }
108
168
  const pubFilePath = `.dev/pub.js`;
109
169
  const edgeRoutinePath = path.join(projectPath, pubFilePath);
110
170
  if (fs.existsSync(edgeRoutinePath)) {
@@ -122,26 +182,57 @@ export function getConfigurations() {
122
182
  return [null, null];
123
183
  }
124
184
  }
125
- export function generateConfigFile(projectName, initConfigs) {
126
- return __awaiter(this, void 0, void 0, function* () {
127
- var _a;
128
- const newFilePath = path.join(process.cwd(), 'esa.toml');
129
- const currentDirName = path.basename(process.cwd());
130
- const entry = ((_a = initConfigs === null || initConfigs === void 0 ? void 0 : initConfigs.dev) === null || _a === void 0 ? void 0 : _a.entry) || 'src/index.js';
185
+ export function generateConfigFile(projectName_1, initConfigs_1, targetDir_1) {
186
+ return __awaiter(this, arguments, void 0, function* (projectName, initConfigs, targetDir, configFormat = 'jsonc', notFoundStrategy) {
187
+ var _a, _b;
188
+ const outputDir = targetDir !== null && targetDir !== void 0 ? targetDir : process.cwd();
189
+ const currentDirName = path.basename(outputDir);
190
+ const entry = (_a = initConfigs === null || initConfigs === void 0 ? void 0 : initConfigs.dev) === null || _a === void 0 ? void 0 : _a.entry;
131
191
  const port = (initConfigs === null || initConfigs === void 0 ? void 0 : initConfigs.port) || 18080;
132
192
  const name = projectName || currentDirName;
193
+ const assetsDirectory = (_b = initConfigs === null || initConfigs === void 0 ? void 0 : initConfigs.assets) === null || _b === void 0 ? void 0 : _b.directory;
194
+ let newFilePath;
195
+ let genConfig;
196
+ if (configFormat === 'jsonc') {
197
+ newFilePath = path.join(outputDir, 'esa.jsonc');
198
+ const configObj = { name };
199
+ if (entry)
200
+ configObj.entry = entry;
201
+ if (assetsDirectory) {
202
+ configObj.assets = { directory: assetsDirectory };
203
+ if (notFoundStrategy) {
204
+ configObj.assets.notFoundStrategy =
205
+ notFoundStrategy;
206
+ }
207
+ }
208
+ configObj.dev = { port };
209
+ genConfig = JSON.stringify(configObj, null, 2) + '\n';
210
+ }
211
+ else {
212
+ // Default to TOML format
213
+ newFilePath = path.join(outputDir, 'esa.toml');
214
+ const configObj = {
215
+ name,
216
+ dev: { port }
217
+ };
218
+ if (entry)
219
+ configObj.entry = entry;
220
+ if (assetsDirectory) {
221
+ configObj.assets = { directory: assetsDirectory };
222
+ if (notFoundStrategy) {
223
+ configObj.assets.notFoundStrategy =
224
+ notFoundStrategy;
225
+ }
226
+ }
227
+ genConfig = toml.stringify(configObj);
228
+ }
133
229
  if (fs.existsSync(newFilePath)) {
134
- logger.error(t('generate_config_error').d('esa.toml already exists'));
230
+ logger.error(`${path.basename(newFilePath)}` +
231
+ t('generate_config_error').d('already exists'));
135
232
  return;
136
233
  }
137
234
  else {
138
- const genConfig = `name = "${name}"
139
- entry = "${entry}"
140
- [dev]
141
- port = ${port}
142
- `;
143
235
  yield fsPromises.writeFile(newFilePath, genConfig, 'utf-8');
144
- logger.success(t('generate_config_success').d('Generated esa.toml'));
145
236
  }
146
237
  });
147
238
  }
@@ -10,10 +10,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  import { exec, execSync } from 'child_process';
11
11
  import os from 'os';
12
12
  import path from 'path';
13
+ import t from '../i18n/index.js';
13
14
  import logger from '../libs/logger.js';
14
- import { getDirName } from './fileUtils/base.js';
15
15
  import { downloadRuntimeAndUnzipForWindows } from './download.js';
16
- import t from '../i18n/index.js';
16
+ import { getDirName } from './fileUtils/base.js';
17
17
  export function preCheckDeno() {
18
18
  return __awaiter(this, void 0, void 0, function* () {
19
19
  const command = yield checkDenoInstalled();
@@ -45,7 +45,7 @@ export function checkDenoInstalled() {
45
45
  .then((res) => {
46
46
  resolve(res);
47
47
  })
48
- .catch((err) => {
48
+ .catch(() => {
49
49
  resolve(false);
50
50
  });
51
51
  });
@@ -66,7 +66,7 @@ export function installDeno() {
66
66
  default:
67
67
  installCommand = `sh ${p}/install.sh`;
68
68
  }
69
- logger.warn(t('install_runtime_tip').d(`🔔 Runtime must be installed to use esa dev. Installing...`));
69
+ logger.warn(t('install_runtime_tip').d(`🔔 Runtime must be installed to use esa-cli dev. Installing...`));
70
70
  try {
71
71
  execSync(installCommand, { stdio: 'inherit' });
72
72
  logger.success(t('install_runtime_success').d(`Runtime installed.`));