esa-cli 0.0.2-beta.2 → 0.0.2-beta.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 (80) hide show
  1. package/dist/commands/commit/index.js +45 -117
  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 +419 -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 +48 -187
  8. package/dist/commands/deployments/delete.js +32 -22
  9. package/dist/commands/deployments/index.js +3 -3
  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 +30 -34
  16. package/dist/commands/dev/ew2/kvService.js +46 -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 -28
  20. package/dist/commands/dev/index.js +16 -16
  21. package/dist/commands/dev/mockWorker/devPack.js +32 -21
  22. package/dist/commands/dev/mockWorker/server.js +7 -6
  23. package/dist/commands/domain/add.js +3 -3
  24. package/dist/commands/domain/delete.js +7 -7
  25. package/dist/commands/domain/index.js +3 -3
  26. package/dist/commands/domain/list.js +10 -10
  27. package/dist/commands/init/helper.js +761 -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 +6 -6
  37. package/dist/commands/route/add.js +138 -49
  38. package/dist/commands/route/delete.js +33 -27
  39. package/dist/commands/route/helper.js +124 -0
  40. package/dist/commands/route/index.js +3 -3
  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 +3 -3
  44. package/dist/commands/routine/list.js +9 -21
  45. package/dist/commands/site/index.js +2 -2
  46. package/dist/commands/site/list.js +6 -7
  47. package/dist/commands/utils.js +55 -19
  48. package/dist/components/descriptionInput.js +1 -1
  49. package/dist/components/mutiLevelSelect.js +43 -55
  50. package/dist/components/mutiSelectTable.js +1 -1
  51. package/dist/components/selectInput.js +2 -3
  52. package/dist/components/selectItem.js +1 -1
  53. package/dist/docs/Commands_en.md +142 -131
  54. package/dist/docs/Commands_zh_CN.md +139 -127
  55. package/dist/i18n/index.js +2 -2
  56. package/dist/i18n/locales.json +401 -21
  57. package/dist/index.js +27 -20
  58. package/dist/libs/api.js +32 -9
  59. package/dist/libs/apiService.js +262 -84
  60. package/dist/libs/git/index.js +86 -9
  61. package/dist/libs/interface.js +0 -1
  62. package/dist/libs/logger.js +162 -10
  63. package/dist/libs/service.js +2 -2
  64. package/dist/libs/templates/index.js +3 -2
  65. package/dist/utils/checkAssetsExist.js +80 -0
  66. package/dist/utils/checkDevPort.js +3 -17
  67. package/dist/utils/checkEntryFileExist.js +10 -0
  68. package/dist/utils/checkIsRoutineCreated.js +27 -26
  69. package/dist/utils/checkVersion.js +119 -1
  70. package/dist/utils/command.js +149 -0
  71. package/dist/utils/compress.js +136 -0
  72. package/dist/utils/download.js +182 -0
  73. package/dist/utils/fileMd5.js +1 -1
  74. package/dist/utils/fileUtils/base.js +1 -1
  75. package/dist/utils/fileUtils/index.js +69 -28
  76. package/dist/utils/installDeno.js +8 -8
  77. package/dist/utils/installEw2.js +7 -7
  78. package/dist/utils/openInBrowser.js +1 -1
  79. package/dist/utils/prompt.js +97 -0
  80. package/package.json +20 -12
@@ -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,136 @@
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('esa.jsonc or esa.toml is not found and script entry or assets directory is not provided by command line');
47
+ exit(0);
48
+ }
49
+ // 参数优先:如果有参数则使用参数,否则使用配置文件中的值
50
+ const entry = scriptEntry || (projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.entry);
51
+ if (routineType === EDGE_ROUTINE_TYPE.NOT_EXIST) {
52
+ const errorMessage = [
53
+ chalk.red.bold('❌ File upload failed'),
54
+ '',
55
+ chalk.cyan('📋 Current configuration information:'),
56
+ `${chalk.white(` 📄 Entry file ${chalk.yellow('(dynamic)')} :`)} ${chalk.yellow(scriptEntry ||
57
+ (projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.entry) ||
58
+ chalk.gray(t('compress_not_configured').d('Not configured')))}`,
59
+ `${chalk.white(` 🗂️ Assets directory ${chalk.yellow('(static)')} :`)} ${chalk.yellow(assetsDirectory || chalk.gray(t('compress_not_configured').d('Not configured')))}`,
60
+ '',
61
+ chalk.cyan('🔍 Possible issue causes:'),
62
+ chalk.white(' 1. Entry file path is incorrect or file does not exist'),
63
+ chalk.white(' 2. Assets directory path is incorrect or directory does not exist'),
64
+ chalk.white(` 3. Project configuration file ${chalk.yellow('esa.jsonc')} or ${chalk.yellow('esa.toml')} format error`),
65
+ chalk.white(` 4. Relative path format error, please use ${chalk.yellow('./xxx')} format`),
66
+ '',
67
+ chalk.yellow.bold(`📍 Please check if the following ${chalk.red('absolute paths')} are correct:`),
68
+ ...(scriptEntry || (projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.entry)
69
+ ? [
70
+ `${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)'))}`
71
+ ]
72
+ : []),
73
+ ...(assetsDirectory
74
+ ? [
75
+ `${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)'))}`
76
+ ]
77
+ : []),
78
+ ...(!scriptEntry && !(projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.entry) && !assetsDirectory
79
+ ? [
80
+ chalk.yellow.bold(' ⚠️ You need to configure at least one of entry file or assets directory')
81
+ ]
82
+ : []),
83
+ ''
84
+ ].join('\n');
85
+ logger.error(errorMessage);
86
+ exit(0);
87
+ }
88
+ if (routineType === EDGE_ROUTINE_TYPE.JS_ONLY ||
89
+ routineType === EDGE_ROUTINE_TYPE.JS_AND_ASSETS) {
90
+ const buildEntry = path.resolve(projectPath !== null && projectPath !== void 0 ? projectPath : '', entry !== null && entry !== void 0 ? entry : '');
91
+ yield prodBuild(minify, buildEntry, projectPath);
92
+ code = readEdgeRoutineFile(projectPath);
93
+ zip.addFile(`routine/index.js`, Buffer.from(code || ''));
94
+ fileList.push('routine/index.js');
95
+ const relativeEntry = path
96
+ .relative(projectPath !== null && projectPath !== void 0 ? projectPath : '', buildEntry)
97
+ .split(path.sep)
98
+ .join('/');
99
+ sourceList.push(relativeEntry);
100
+ dynamicSources.push(relativeEntry);
101
+ }
102
+ assetsDirectory = path.resolve(projectPath !== null && projectPath !== void 0 ? projectPath : '', assetsDirectory !== null && assetsDirectory !== void 0 ? assetsDirectory : '');
103
+ // Add all files in the assets directory to the /assets directory
104
+ if ((routineType === EDGE_ROUTINE_TYPE.JS_AND_ASSETS ||
105
+ routineType === EDGE_ROUTINE_TYPE.ASSETS_ONLY) &&
106
+ assetsDirectory &&
107
+ fs.existsSync(assetsDirectory)) {
108
+ const addDirectoryToZip = (dirPath, zipPath) => {
109
+ const files = fs.readdirSync(dirPath);
110
+ for (const file of files) {
111
+ const fullPath = path.join(dirPath, file);
112
+ const stat = fs.statSync(fullPath);
113
+ if (stat.isDirectory()) {
114
+ addDirectoryToZip(fullPath, path.join(zipPath, file));
115
+ }
116
+ else {
117
+ const fileContent = fs.readFileSync(fullPath);
118
+ const relativePath = path
119
+ .relative(assetsDirectory, fullPath)
120
+ .split(path.sep)
121
+ .join('/');
122
+ zip.addFile(`assets/${relativePath}`, fileContent);
123
+ fileList.push(`assets/${relativePath}`);
124
+ const relativeSrcPath = path
125
+ .relative(projectPath !== null && projectPath !== void 0 ? projectPath : '', fullPath)
126
+ .split(path.sep)
127
+ .join('/');
128
+ sourceList.push(relativeSrcPath);
129
+ }
130
+ }
131
+ };
132
+ addDirectoryToZip(assetsDirectory, 'assets');
133
+ }
134
+ return { zip, fileList, sourceList, dynamicSources };
135
+ });
136
+ export default compress;
@@ -0,0 +1,182 @@
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 { exec } from 'child_process';
11
+ import * as fs from 'fs/promises';
12
+ import os from 'os';
13
+ import * as path from 'path';
14
+ import { promisify } from 'util';
15
+ import AdmZip from 'adm-zip';
16
+ import chalk from 'chalk';
17
+ import fetch from 'node-fetch';
18
+ import t from '../i18n/index.js';
19
+ import logger from '../libs/logger.js';
20
+ const execAsync = promisify(exec);
21
+ function getBinDir() {
22
+ const home = os.homedir();
23
+ return path.join(home || '', '.deno', 'bin');
24
+ }
25
+ /**
26
+ * 下载文件
27
+ * @param url 远程文件URL
28
+ * @param dest 本地保存路径
29
+ */
30
+ export function downloadFile(url, dest) {
31
+ return __awaiter(this, void 0, void 0, function* () {
32
+ const response = yield fetch(url);
33
+ if (!response.ok) {
34
+ throw new Error(`Error downloading file: ${response.status} ${response.statusText}`);
35
+ }
36
+ const fileStream = yield fs.open(dest, 'w');
37
+ return new Promise((resolve, reject) => {
38
+ var _a, _b;
39
+ (_a = response.body) === null || _a === void 0 ? void 0 : _a.pipe(fileStream.createWriteStream());
40
+ (_b = response.body) === null || _b === void 0 ? void 0 : _b.on('error', (err) => {
41
+ fileStream.close();
42
+ reject(err);
43
+ });
44
+ fileStream.createWriteStream().on('finish', () => {
45
+ fileStream.close();
46
+ resolve();
47
+ });
48
+ });
49
+ });
50
+ }
51
+ /**
52
+ * 解压Zip文件 adm 是同步的
53
+ * @param zipPath Zip文件路径
54
+ * @param extractPath 解压目标目录
55
+ */
56
+ export function unzipFile(zipPath, extractPath) {
57
+ const zip = new AdmZip(zipPath);
58
+ zip.extractAllTo(extractPath, true);
59
+ logger.info(`UnzipFile success: from ${zipPath} to ${extractPath}`);
60
+ }
61
+ /**
62
+ * 获取用户的 PATH 环境变量(win下专用)
63
+ * @returns 用户 PATH
64
+ */
65
+ function getUserPath() {
66
+ return __awaiter(this, void 0, void 0, function* () {
67
+ const { stdout } = yield execAsync('reg query "HKCU\\Environment" /v Path');
68
+ const match = stdout.match(/Path\s+REG_EXPAND_SZ\s+(.*)/i);
69
+ if (match && match[1]) {
70
+ return match[1].trim();
71
+ }
72
+ return '';
73
+ });
74
+ }
75
+ /**
76
+ * 检查 BinDir 是否在用户的 PATH 中(win下专用)
77
+ * @param binDir BinDir 路径
78
+ * @returns 是否包含
79
+ */
80
+ function isBinDirInPath(binDir) {
81
+ return __awaiter(this, void 0, void 0, function* () {
82
+ const userPath = yield getUserPath();
83
+ return userPath
84
+ .split(';')
85
+ .map((p) => p.toLowerCase())
86
+ .includes(binDir.toLowerCase());
87
+ });
88
+ }
89
+ /**
90
+ * 将 BinDir 添加到用户的 PATH 环境变量(win下专用)
91
+ * @param binDir BinDir 路径
92
+ */
93
+ function addBinDirToPath(binDir) {
94
+ return __awaiter(this, void 0, void 0, function* () {
95
+ // 使用 setx 添加到 PATH
96
+ // setx 对 PATH 的长度有2047字符的限制
97
+ const command = `setx Path "%Path%;${binDir}"`;
98
+ try {
99
+ yield execAsync(command);
100
+ logger.info(`Path add success: ${binDir}`);
101
+ }
102
+ catch (error) {
103
+ throw new Error(`Add BinDir to Path failed: ${error}`);
104
+ }
105
+ });
106
+ }
107
+ export function downloadRuntimeAndUnzipForWindows() {
108
+ return __awaiter(this, void 0, void 0, function* () {
109
+ try {
110
+ const BinDir = getBinDir();
111
+ const DenoZip = path.join(BinDir, 'deno.zip');
112
+ const Target = 'x86_64-pc-windows-msvc';
113
+ const DownloadUrl = `http://esa-runtime.myalicdn.com/runtime/deno-${Target}.zip`;
114
+ logger.ora.start('Downloading...');
115
+ try {
116
+ yield fs.mkdir(BinDir, { recursive: true });
117
+ }
118
+ catch (error) {
119
+ const err = error;
120
+ logger.ora.fail();
121
+ logger.error(`mkdir error ${BinDir}: ${err.message}`);
122
+ process.exit(1);
123
+ }
124
+ try {
125
+ yield downloadFile(DownloadUrl, DenoZip);
126
+ }
127
+ catch (error) {
128
+ const err = error;
129
+ logger.ora.fail();
130
+ logger.error(`${t('deno_download_failed').d('Download failed')}: ${err.message}`);
131
+ process.exit(1);
132
+ }
133
+ logger.info(`Unzip file to: ${BinDir}`);
134
+ try {
135
+ logger.ora.text = 'Unzip...';
136
+ unzipFile(DenoZip, BinDir);
137
+ }
138
+ catch (error) {
139
+ const err = error;
140
+ logger.ora.fail();
141
+ logger.error(`${t('deno_unzip_failed').d('Unzip failed')}: ${err.message}`);
142
+ process.exit(1);
143
+ }
144
+ try {
145
+ logger.ora.text = 'Deleting temp file...';
146
+ yield fs.unlink(DenoZip);
147
+ logger.ora.succeed('Download success');
148
+ logger.info(`Delete temp file: ${DenoZip}`);
149
+ }
150
+ catch (error) {
151
+ logger.warn(`Delete temp file ${DenoZip} failed: ${error}`);
152
+ }
153
+ try {
154
+ logger.ora.text = 'Adding Bin dir to PATH...';
155
+ const inPath = yield isBinDirInPath(BinDir);
156
+ if (!inPath) {
157
+ logger.info(`${BinDir} not in PATH`);
158
+ yield addBinDirToPath(BinDir);
159
+ }
160
+ else {
161
+ logger.info(`${BinDir} in PATH already`);
162
+ }
163
+ }
164
+ catch (error) {
165
+ const err = error;
166
+ logger.ora.fail();
167
+ logger.error(`${t('deno_add_path_failed').d('Add BinDir to Path failed')}: ${err.message}`);
168
+ process.exit(1);
169
+ }
170
+ logger.success(t('deno_install_success').d('Runtime install success!'));
171
+ logger.block();
172
+ const dev = chalk.green('esa dev');
173
+ logger.log(t('deno_install_success_tips', { dev }).d(`Please run ${dev} again`));
174
+ }
175
+ catch (error) {
176
+ const err = error;
177
+ logger.ora.fail();
178
+ logger.error(`Download Error: ${err.message}`);
179
+ process.exit(1);
180
+ }
181
+ });
182
+ }
@@ -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');
@@ -11,7 +11,7 @@ export const getRoot = (root) => {
11
11
  if (typeof root === 'undefined') {
12
12
  root = process.cwd();
13
13
  }
14
- if (root === '/') {
14
+ if (path.parse(root).root === root) {
15
15
  return process.cwd();
16
16
  }
17
17
  const file = path.join(root, cliConfigFile);
@@ -7,14 +7,13 @@ 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';
15
+ import logger from '../../libs/logger.js';
16
+ import { getDirName, getRoot } from './base.js';
18
17
  const projectConfigFile = 'esa.toml';
19
18
  const __dirname = getDirName(import.meta.url);
20
19
  const root = getRoot();
@@ -76,11 +75,21 @@ export function readConfigFile(configPath) {
76
75
  if (fs.existsSync(configPath)) {
77
76
  const configFileContent = fs.readFileSync(configPath, 'utf-8');
78
77
  try {
79
- const config = toml.parse(configFileContent);
80
- return config;
78
+ if (configPath.endsWith('.jsonc') || configPath.endsWith('.json')) {
79
+ // Remove comments for JSON parsing
80
+ const jsonContent = configFileContent.replace(/\/\*[\s\S]*?\*\/|\/\/.*$/gm, '');
81
+ const config = JSON.parse(jsonContent);
82
+ return config;
83
+ }
84
+ else {
85
+ // TOML format
86
+ const config = toml.parse(configFileContent);
87
+ return config;
88
+ }
81
89
  }
82
90
  catch (error) {
83
- logger.error(`Error parsing TOML file: ${error}`);
91
+ console.log(error);
92
+ logger.error(`Error parsing config file: ${error}`);
84
93
  return null;
85
94
  }
86
95
  }
@@ -94,17 +103,18 @@ export function getCliConfig() {
94
103
  return res;
95
104
  }
96
105
  export function getProjectConfig(filePath = root) {
97
- const res = readConfigFile(path.join(filePath, projectConfigFile));
98
- if (!res) {
99
- return null;
106
+ // Try to find config file in order of preference: .jsonc, .toml
107
+ const configFormats = ['esa.jsonc', 'esa.toml'];
108
+ for (const format of configFormats) {
109
+ const configPath = path.join(filePath, format);
110
+ const config = readConfigFile(configPath);
111
+ if (config) {
112
+ return config;
113
+ }
100
114
  }
101
- return res;
115
+ return null;
102
116
  }
103
117
  export function readEdgeRoutineFile(projectPath = root) {
104
- const projectConfig = getProjectConfig(projectPath);
105
- if (!projectConfig) {
106
- return null;
107
- }
108
118
  const pubFilePath = `.dev/pub.js`;
109
119
  const edgeRoutinePath = path.join(projectPath, pubFilePath);
110
120
  if (fs.existsSync(edgeRoutinePath)) {
@@ -122,26 +132,57 @@ export function getConfigurations() {
122
132
  return [null, null];
123
133
  }
124
134
  }
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';
135
+ export function generateConfigFile(projectName_1, initConfigs_1, targetDir_1) {
136
+ return __awaiter(this, arguments, void 0, function* (projectName, initConfigs, targetDir, configFormat = 'toml', notFoundStrategy) {
137
+ var _a, _b;
138
+ const outputDir = targetDir !== null && targetDir !== void 0 ? targetDir : process.cwd();
139
+ const currentDirName = path.basename(outputDir);
140
+ const entry = (_a = initConfigs === null || initConfigs === void 0 ? void 0 : initConfigs.dev) === null || _a === void 0 ? void 0 : _a.entry;
131
141
  const port = (initConfigs === null || initConfigs === void 0 ? void 0 : initConfigs.port) || 18080;
132
142
  const name = projectName || currentDirName;
143
+ const assetsDirectory = (_b = initConfigs === null || initConfigs === void 0 ? void 0 : initConfigs.assets) === null || _b === void 0 ? void 0 : _b.directory;
144
+ let newFilePath;
145
+ let genConfig;
146
+ if (configFormat === 'jsonc') {
147
+ newFilePath = path.join(outputDir, 'esa.jsonc');
148
+ const configObj = { name };
149
+ if (entry)
150
+ configObj.entry = entry;
151
+ if (assetsDirectory) {
152
+ configObj.assets = { directory: assetsDirectory };
153
+ if (notFoundStrategy) {
154
+ configObj.assets.notFoundStrategy =
155
+ notFoundStrategy;
156
+ }
157
+ }
158
+ configObj.dev = { port };
159
+ genConfig = JSON.stringify(configObj, null, 2) + '\n';
160
+ }
161
+ else {
162
+ // Default to TOML format
163
+ newFilePath = path.join(outputDir, 'esa.toml');
164
+ const configObj = {
165
+ name,
166
+ dev: { port }
167
+ };
168
+ if (entry)
169
+ configObj.entry = entry;
170
+ if (assetsDirectory) {
171
+ configObj.assets = { directory: assetsDirectory };
172
+ if (notFoundStrategy) {
173
+ configObj.assets.notFoundStrategy =
174
+ notFoundStrategy;
175
+ }
176
+ }
177
+ genConfig = toml.stringify(configObj);
178
+ }
133
179
  if (fs.existsSync(newFilePath)) {
134
- logger.error(t('generate_config_error').d('esa.toml already exists'));
180
+ logger.error(`${path.basename(newFilePath)}` +
181
+ t('generate_config_error').d('already exists'));
135
182
  return;
136
183
  }
137
184
  else {
138
- const genConfig = `name = "${name}"
139
- entry = "${entry}"
140
- [dev]
141
- port = ${port}
142
- `;
143
185
  yield fsPromises.writeFile(newFilePath, genConfig, 'utf-8');
144
- logger.success(t('generate_config_success').d('Generated esa.toml'));
145
186
  }
146
187
  });
147
188
  }
@@ -9,16 +9,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { exec, execSync } from 'child_process';
11
11
  import os from 'os';
12
- import { getDirName } from './fileUtils/base.js';
13
- import logger from '../libs/logger.js';
14
12
  import path from 'path';
15
13
  import t from '../i18n/index.js';
14
+ import logger from '../libs/logger.js';
15
+ import { downloadRuntimeAndUnzipForWindows } from './download.js';
16
+ import { getDirName } from './fileUtils/base.js';
16
17
  export function preCheckDeno() {
17
18
  return __awaiter(this, void 0, void 0, function* () {
18
19
  const command = yield checkDenoInstalled();
19
20
  if (!command) {
20
- logger.error(t('install_runtime_explain').d('Under the beta phase, we are temporarily using Deno as the local development runtime. It needs to be installed first.'));
21
- installDeno();
21
+ logger.error(t('install_runtime_explain').d('Our runtime does not yet support this OS. We are temporarily using Deno as the local development runtime, which needs to be installed first.'));
22
+ yield installDeno();
22
23
  return false;
23
24
  }
24
25
  return command;
@@ -44,8 +45,7 @@ export function checkDenoInstalled() {
44
45
  .then((res) => {
45
46
  resolve(res);
46
47
  })
47
- .catch((err) => {
48
- console.log(err);
48
+ .catch(() => {
49
49
  resolve(false);
50
50
  });
51
51
  });
@@ -57,8 +57,8 @@ export function installDeno() {
57
57
  const p = path.join(__dirname, './install');
58
58
  switch (os.platform()) {
59
59
  case 'win32':
60
- installCommand = `powershell.exe -Command "Get-Content '${p}/install.ps1' | iex"`;
61
- break;
60
+ yield downloadRuntimeAndUnzipForWindows();
61
+ return true;
62
62
  case 'darwin':
63
63
  case 'linux':
64
64
  installCommand = `sh ${p}/install.sh`;