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.
- package/dist/commands/commit/index.js +45 -117
- package/dist/commands/commit/prodBuild.js +2 -3
- package/dist/commands/common/constant.js +0 -19
- package/dist/commands/common/utils.js +419 -0
- package/dist/commands/config.js +1 -1
- package/dist/commands/deploy/helper.js +51 -72
- package/dist/commands/deploy/index.js +48 -187
- package/dist/commands/deployments/delete.js +32 -22
- package/dist/commands/deployments/index.js +3 -3
- package/dist/commands/deployments/list.js +22 -38
- package/dist/commands/dev/build.js +3 -3
- package/dist/commands/dev/doProcess.js +5 -5
- package/dist/commands/dev/ew2/cacheService.js +33 -0
- package/dist/commands/dev/ew2/devEntry.js +2 -1
- package/dist/commands/dev/ew2/devPack.js +30 -34
- package/dist/commands/dev/ew2/kvService.js +46 -0
- package/dist/commands/dev/ew2/mock/cache.js +99 -15
- package/dist/commands/dev/ew2/mock/kv.js +142 -21
- package/dist/commands/dev/ew2/server.js +165 -28
- package/dist/commands/dev/index.js +16 -16
- package/dist/commands/dev/mockWorker/devPack.js +32 -21
- package/dist/commands/dev/mockWorker/server.js +7 -6
- package/dist/commands/domain/add.js +3 -3
- package/dist/commands/domain/delete.js +7 -7
- package/dist/commands/domain/index.js +3 -3
- package/dist/commands/domain/list.js +10 -10
- package/dist/commands/init/helper.js +761 -0
- package/dist/commands/init/index.js +88 -220
- package/dist/commands/init/snippets/nextjs/next.config.mjs +6 -0
- package/dist/commands/init/snippets/nextjs/next.config.ts +7 -0
- package/dist/commands/init/snippets/react-router/react-router.config.ts +7 -0
- package/dist/commands/init/template.jsonc +84 -0
- package/dist/commands/init/types.js +1 -0
- package/dist/commands/lang.js +2 -2
- package/dist/commands/login/index.js +74 -34
- package/dist/commands/logout.js +6 -6
- package/dist/commands/route/add.js +138 -49
- package/dist/commands/route/delete.js +33 -27
- package/dist/commands/route/helper.js +124 -0
- package/dist/commands/route/index.js +3 -3
- package/dist/commands/route/list.js +56 -17
- package/dist/commands/routine/delete.js +2 -2
- package/dist/commands/routine/index.js +3 -3
- package/dist/commands/routine/list.js +9 -21
- package/dist/commands/site/index.js +2 -2
- package/dist/commands/site/list.js +6 -7
- package/dist/commands/utils.js +55 -19
- package/dist/components/descriptionInput.js +1 -1
- package/dist/components/mutiLevelSelect.js +43 -55
- package/dist/components/mutiSelectTable.js +1 -1
- package/dist/components/selectInput.js +2 -3
- package/dist/components/selectItem.js +1 -1
- package/dist/docs/Commands_en.md +142 -131
- package/dist/docs/Commands_zh_CN.md +139 -127
- package/dist/i18n/index.js +2 -2
- package/dist/i18n/locales.json +401 -21
- package/dist/index.js +27 -20
- package/dist/libs/api.js +32 -9
- package/dist/libs/apiService.js +262 -84
- package/dist/libs/git/index.js +86 -9
- package/dist/libs/interface.js +0 -1
- package/dist/libs/logger.js +162 -10
- package/dist/libs/service.js +2 -2
- package/dist/libs/templates/index.js +3 -2
- package/dist/utils/checkAssetsExist.js +80 -0
- package/dist/utils/checkDevPort.js +3 -17
- package/dist/utils/checkEntryFileExist.js +10 -0
- package/dist/utils/checkIsRoutineCreated.js +27 -26
- package/dist/utils/checkVersion.js +119 -1
- package/dist/utils/command.js +149 -0
- package/dist/utils/compress.js +136 -0
- package/dist/utils/download.js +182 -0
- package/dist/utils/fileMd5.js +1 -1
- package/dist/utils/fileUtils/base.js +1 -1
- package/dist/utils/fileUtils/index.js +69 -28
- package/dist/utils/installDeno.js +8 -8
- package/dist/utils/installEw2.js +7 -7
- package/dist/utils/openInBrowser.js +1 -1
- package/dist/utils/prompt.js +97 -0
- 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
|
+
}
|
package/dist/utils/fileMd5.js
CHANGED
|
@@ -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
|
-
|
|
80
|
-
|
|
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
|
-
|
|
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
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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
|
|
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(
|
|
126
|
-
return __awaiter(this,
|
|
127
|
-
var _a;
|
|
128
|
-
const
|
|
129
|
-
const currentDirName = path.basename(
|
|
130
|
-
const entry = (
|
|
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(
|
|
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('
|
|
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((
|
|
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
|
-
|
|
61
|
-
|
|
60
|
+
yield downloadRuntimeAndUnzipForWindows();
|
|
61
|
+
return true;
|
|
62
62
|
case 'darwin':
|
|
63
63
|
case 'linux':
|
|
64
64
|
installCommand = `sh ${p}/install.sh`;
|