esa-cli 0.0.2-beta.13 → 0.0.2-beta.15
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 +22 -4
- package/dist/commands/common/{routineUtils.js → utils.js} +104 -58
- package/dist/commands/deploy/index.js +11 -51
- package/dist/commands/init/helper.js +482 -6
- package/dist/commands/init/index.js +62 -530
- 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 +54 -4
- package/dist/commands/init/types.js +1 -0
- package/dist/commands/login/index.js +18 -28
- package/dist/commands/utils.js +1 -1
- package/dist/components/mutiLevelSelect.js +18 -20
- package/dist/docs/Commands_en.md +111 -143
- package/dist/docs/Commands_zh_CN.md +111 -143
- package/dist/i18n/locales.json +76 -20
- package/dist/libs/apiService.js +8 -3
- package/dist/libs/git/index.js +80 -7
- package/dist/libs/logger.js +64 -7
- package/dist/utils/checkIsRoutineCreated.js +16 -4
- package/dist/utils/command.js +149 -0
- package/dist/utils/compress.js +42 -4
- package/dist/utils/fileUtils/index.js +30 -34
- package/dist/utils/prompt.js +97 -0
- package/package.json +3 -1
- package/dist/docs/eslint-config-en.md +0 -1
- package/dist/docs/eslint-config.md +0 -73
- package/dist/docs/init-command-quick-test.md +0 -208
- package/dist/docs/init-command-test-guide.md +0 -598
package/dist/libs/logger.js
CHANGED
|
@@ -17,6 +17,7 @@ const transport = new DailyRotateFile({
|
|
|
17
17
|
});
|
|
18
18
|
class Logger {
|
|
19
19
|
constructor() {
|
|
20
|
+
this.spinnerText = '';
|
|
20
21
|
const { combine, timestamp, label, printf } = format;
|
|
21
22
|
const customFormat = printf(({ level, message, label: printLabel, timestamp: printTimestamp }) => {
|
|
22
23
|
var _a;
|
|
@@ -65,6 +66,60 @@ class Logger {
|
|
|
65
66
|
setLogLevel(level) {
|
|
66
67
|
this.logger.level = level;
|
|
67
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Start a sub-step: show a spinner with the provided message.
|
|
71
|
+
* If a spinner is already running, just update its text.
|
|
72
|
+
*/
|
|
73
|
+
startSubStep(message) {
|
|
74
|
+
this.spinnerText = message;
|
|
75
|
+
this.spinner.text = message;
|
|
76
|
+
if (!this.spinner.isSpinning) {
|
|
77
|
+
this.spinner.start();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* End a sub-step: stop loading and replace spinner with `├` and final message.
|
|
82
|
+
* This overwrites the previous spinner line with the provided message.
|
|
83
|
+
*/
|
|
84
|
+
endSubStep(message) {
|
|
85
|
+
// console.log(chalk.gray('├') + ' ' + this.spinnerText);
|
|
86
|
+
try {
|
|
87
|
+
if (this.spinner && this.spinner.isSpinning) {
|
|
88
|
+
this.spinner.stop();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch (_a) { }
|
|
92
|
+
console.log(chalk.gray(`│ `));
|
|
93
|
+
console.log(chalk.gray('├ ') + this.spinnerText);
|
|
94
|
+
console.log(chalk.gray(`│ ${message}`));
|
|
95
|
+
}
|
|
96
|
+
stopSpinner() {
|
|
97
|
+
try {
|
|
98
|
+
if (this.spinner && this.spinner.isSpinning) {
|
|
99
|
+
this.spinner.stop();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch (_a) { }
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Prepare terminal output just before showing an interactive prompt.
|
|
106
|
+
* - Stops any active spinner
|
|
107
|
+
* - Replaces the previous line with a clean `╰ <text>` indicator
|
|
108
|
+
*/
|
|
109
|
+
prepareForPrompt(text) {
|
|
110
|
+
this.stopSpinner();
|
|
111
|
+
const content = `╰ ${text || ''}`;
|
|
112
|
+
this.replacePrevLine(content);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Consolidate interactive prompt output after completion by replacing
|
|
116
|
+
* the previous N lines with a concise summary line.
|
|
117
|
+
* Defaults to 2 lines (prompt + answer line in most cases).
|
|
118
|
+
*/
|
|
119
|
+
consolidateAfterPrompt(summary, linesToReplace = 2) {
|
|
120
|
+
const content = `├ ${summary}`;
|
|
121
|
+
this.replacePrevLines(linesToReplace, content);
|
|
122
|
+
}
|
|
68
123
|
log(message) {
|
|
69
124
|
console.log(message);
|
|
70
125
|
}
|
|
@@ -155,25 +210,27 @@ class Logger {
|
|
|
155
210
|
}
|
|
156
211
|
console.log(lines.join('\n'));
|
|
157
212
|
}
|
|
158
|
-
|
|
159
|
-
cfStepHeader(title, step, total) {
|
|
213
|
+
StepHeader(title, step, total) {
|
|
160
214
|
console.log(`\n╭ ${title} ${chalk.green(`Step ${step} of ${total}`)}`);
|
|
161
215
|
console.log('│');
|
|
162
216
|
}
|
|
163
|
-
|
|
217
|
+
StepItem(prompt) {
|
|
164
218
|
console.log(`├ ${prompt}`);
|
|
165
219
|
}
|
|
166
|
-
|
|
220
|
+
StepStart(prompt) {
|
|
221
|
+
console.log(`╭ ${prompt}`);
|
|
222
|
+
}
|
|
223
|
+
StepKV(key, value) {
|
|
167
224
|
const orange = chalk.hex('#FFA500');
|
|
168
225
|
console.log(`│ ${orange(key)} ${value}`);
|
|
169
226
|
}
|
|
170
|
-
|
|
227
|
+
StepSpacer() {
|
|
171
228
|
console.log('│');
|
|
172
229
|
}
|
|
173
|
-
|
|
230
|
+
StepEnd(str) {
|
|
174
231
|
console.log(`╰ ${str || ''}`);
|
|
175
232
|
}
|
|
176
|
-
|
|
233
|
+
StepEndInline() {
|
|
177
234
|
try {
|
|
178
235
|
process.stdout.write('╰ ');
|
|
179
236
|
}
|
|
@@ -12,6 +12,7 @@ import chalk from 'chalk';
|
|
|
12
12
|
import t from '../i18n/index.js';
|
|
13
13
|
import { ApiService } from '../libs/apiService.js';
|
|
14
14
|
import logger from '../libs/logger.js';
|
|
15
|
+
import { log } from '@clack/prompts';
|
|
15
16
|
export function isRoutineExist(name) {
|
|
16
17
|
return __awaiter(this, void 0, void 0, function* () {
|
|
17
18
|
const server = yield ApiService.getInstance();
|
|
@@ -38,20 +39,31 @@ export function ensureRoutineExists(name) {
|
|
|
38
39
|
const isExist = yield isRoutineExist(name);
|
|
39
40
|
// If routine does not exist, create a new routine
|
|
40
41
|
if (!isExist) {
|
|
41
|
-
logger.
|
|
42
|
+
logger.startSubStep(`Creating routine ${chalk.gray(name)}`);
|
|
42
43
|
const server = yield ApiService.getInstance();
|
|
43
44
|
const createRes = yield server.createRoutine({
|
|
44
45
|
name: name,
|
|
45
|
-
description: ''
|
|
46
|
+
description: '',
|
|
47
|
+
hasAssets: true
|
|
46
48
|
});
|
|
47
49
|
const isSuccess = (createRes === null || createRes === void 0 ? void 0 : createRes.data.Status) === 'OK';
|
|
48
50
|
if (isSuccess) {
|
|
49
|
-
logger.
|
|
51
|
+
// logger.endSubStep(
|
|
52
|
+
// t('routine_create_success').d('Routine created successfully.')
|
|
53
|
+
// );
|
|
54
|
+
logger.endSubStep('Routine created successfully');
|
|
55
|
+
// tlog.success(
|
|
56
|
+
// t('routine_create_success').d('Routine created successfully.')
|
|
57
|
+
// );
|
|
50
58
|
}
|
|
51
59
|
else {
|
|
52
|
-
logger.
|
|
60
|
+
logger.endSubStep('Routine created failed');
|
|
61
|
+
// tlog.error(t('routine_create_fail').d('Routine created failed.'));
|
|
53
62
|
exit();
|
|
54
63
|
}
|
|
55
64
|
}
|
|
65
|
+
else {
|
|
66
|
+
log.step('Routine has already exists');
|
|
67
|
+
}
|
|
56
68
|
});
|
|
57
69
|
}
|
|
@@ -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;
|
package/dist/utils/compress.js
CHANGED
|
@@ -24,8 +24,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
24
24
|
};
|
|
25
25
|
import fs from 'fs';
|
|
26
26
|
import path from 'path';
|
|
27
|
+
import { exit } from 'process';
|
|
27
28
|
import AdmZip from 'adm-zip';
|
|
29
|
+
import chalk from 'chalk';
|
|
28
30
|
import prodBuild from '../commands/commit/prodBuild.js';
|
|
31
|
+
import t from '../i18n/index.js';
|
|
32
|
+
import logger from '../libs/logger.js';
|
|
29
33
|
import { checkEdgeRoutineType, EDGE_ROUTINE_TYPE } from './checkAssetsExist.js';
|
|
30
34
|
import { getProjectConfig, readEdgeRoutineFile } from './fileUtils/index.js';
|
|
31
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) {
|
|
@@ -33,15 +37,51 @@ const compress = (scriptEntry_1, assetsDir_1, ...args_1) => __awaiter(void 0, [s
|
|
|
33
37
|
let code;
|
|
34
38
|
const zip = new AdmZip();
|
|
35
39
|
const projectConfig = getProjectConfig(projectPath);
|
|
40
|
+
let assetsDirectory = assetsDir || ((_a = projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.assets) === null || _a === void 0 ? void 0 : _a.directory);
|
|
41
|
+
assetsDirectory = path.resolve(projectPath !== null && projectPath !== void 0 ? projectPath : '', assetsDirectory !== null && assetsDirectory !== void 0 ? assetsDirectory : '');
|
|
36
42
|
const routineType = checkEdgeRoutineType(scriptEntry, assetsDir, projectPath);
|
|
37
43
|
if (!projectConfig) {
|
|
38
44
|
throw new Error('Project config not found');
|
|
39
45
|
}
|
|
40
46
|
// 参数优先:如果有参数则使用参数,否则使用配置文件中的值
|
|
41
47
|
const entry = scriptEntry || (projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.entry);
|
|
42
|
-
let assetsDirectory = assetsDir || ((_a = projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.assets) === null || _a === void 0 ? void 0 : _a.directory);
|
|
43
48
|
if (routineType === EDGE_ROUTINE_TYPE.NOT_EXIST) {
|
|
44
|
-
|
|
49
|
+
const errorMessage = [
|
|
50
|
+
chalk.red.bold('❌ File upload failed'),
|
|
51
|
+
'',
|
|
52
|
+
chalk.cyan('📋 Current configuration information:'),
|
|
53
|
+
`${chalk.white(' 📁 Project path:')} ${chalk.yellow(projectPath || chalk.gray(t('compress_not_specified').d('Not specified')))}`,
|
|
54
|
+
`${chalk.white(' 📄 Entry file:')} ${chalk.yellow(scriptEntry ||
|
|
55
|
+
(projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.entry) ||
|
|
56
|
+
chalk.gray(t('compress_not_configured').d('Not configured')))}`,
|
|
57
|
+
`${chalk.white(' 🗂️ Assets directory:')} ${chalk.yellow(assetsDirectory || chalk.gray(t('compress_not_configured').d('Not configured')))}`,
|
|
58
|
+
'',
|
|
59
|
+
chalk.cyan('🔍 Possible issue causes:'),
|
|
60
|
+
chalk.white(' 1. Entry file path is incorrect or file does not exist'),
|
|
61
|
+
chalk.white(' 2. Assets directory path is incorrect or directory does not exist'),
|
|
62
|
+
chalk.white(` 3. Project configuration file ${chalk.yellow('esa.jsonc')} or ${chalk.yellow('esa.toml')} format error`),
|
|
63
|
+
chalk.white(` 4. Relative path format error, please use ${chalk.yellow('./xxx')} format`),
|
|
64
|
+
'',
|
|
65
|
+
chalk.yellow.bold(`📍 Please check if the following ${chalk.red('absolute paths')} are correct:`),
|
|
66
|
+
...(scriptEntry || (projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.entry)
|
|
67
|
+
? [
|
|
68
|
+
`${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)'))}`
|
|
69
|
+
]
|
|
70
|
+
: []),
|
|
71
|
+
...(assetsDirectory
|
|
72
|
+
? [
|
|
73
|
+
`${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)'))}`
|
|
74
|
+
]
|
|
75
|
+
: []),
|
|
76
|
+
...(!scriptEntry && !(projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.entry) && !assetsDirectory
|
|
77
|
+
? [
|
|
78
|
+
chalk.yellow.bold(' ⚠️ You need to configure at least one of entry file or assets directory')
|
|
79
|
+
]
|
|
80
|
+
: []),
|
|
81
|
+
''
|
|
82
|
+
].join('\n');
|
|
83
|
+
logger.error(errorMessage);
|
|
84
|
+
exit(0);
|
|
45
85
|
}
|
|
46
86
|
if (routineType === EDGE_ROUTINE_TYPE.JS_ONLY ||
|
|
47
87
|
routineType === EDGE_ROUTINE_TYPE.JS_AND_ASSETS) {
|
|
@@ -73,8 +113,6 @@ const compress = (scriptEntry_1, assetsDir_1, ...args_1) => __awaiter(void 0, [s
|
|
|
73
113
|
};
|
|
74
114
|
addDirectoryToZip(assetsDirectory, 'assets');
|
|
75
115
|
}
|
|
76
|
-
//输出zip
|
|
77
|
-
zip.writeZip('testassets.zip');
|
|
78
116
|
return zip;
|
|
79
117
|
});
|
|
80
118
|
export default compress;
|
|
@@ -88,6 +88,7 @@ export function readConfigFile(configPath) {
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
catch (error) {
|
|
91
|
+
console.log(error);
|
|
91
92
|
logger.error(`Error parsing config file: ${error}`);
|
|
92
93
|
return null;
|
|
93
94
|
}
|
|
@@ -136,7 +137,7 @@ export function getConfigurations() {
|
|
|
136
137
|
}
|
|
137
138
|
}
|
|
138
139
|
export function generateConfigFile(projectName_1, initConfigs_1, targetDir_1) {
|
|
139
|
-
return __awaiter(this, arguments, void 0, function* (projectName, initConfigs, targetDir, configFormat = 'toml',
|
|
140
|
+
return __awaiter(this, arguments, void 0, function* (projectName, initConfigs, targetDir, configFormat = 'toml', notFoundStrategy) {
|
|
140
141
|
var _a, _b;
|
|
141
142
|
const outputDir = targetDir !== null && targetDir !== void 0 ? targetDir : process.cwd();
|
|
142
143
|
const currentDirName = path.basename(outputDir);
|
|
@@ -148,45 +149,40 @@ export function generateConfigFile(projectName_1, initConfigs_1, targetDir_1) {
|
|
|
148
149
|
let genConfig;
|
|
149
150
|
if (configFormat === 'jsonc') {
|
|
150
151
|
newFilePath = path.join(outputDir, 'esa.jsonc');
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
"entry": "${entry}"`
|
|
164
|
-
: '';
|
|
165
|
-
genConfig = `{
|
|
166
|
-
"name": "${name}"${entryBlock}${assetsBlock},
|
|
167
|
-
"dev": {
|
|
168
|
-
"port": ${port}
|
|
169
|
-
}
|
|
170
|
-
}`;
|
|
152
|
+
const configObj = { name };
|
|
153
|
+
if (entry)
|
|
154
|
+
configObj.entry = entry;
|
|
155
|
+
if (assetsDirectory) {
|
|
156
|
+
configObj.assets = { directory: assetsDirectory };
|
|
157
|
+
if (notFoundStrategy) {
|
|
158
|
+
configObj.assets.notFoundStrategy =
|
|
159
|
+
notFoundStrategy;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
configObj.dev = { port };
|
|
163
|
+
genConfig = JSON.stringify(configObj, null, 2) + '\n';
|
|
171
164
|
}
|
|
172
165
|
else {
|
|
173
166
|
// Default to TOML format
|
|
174
167
|
newFilePath = path.join(outputDir, 'esa.toml');
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
168
|
+
const configObj = {
|
|
169
|
+
name,
|
|
170
|
+
dev: { port }
|
|
171
|
+
};
|
|
172
|
+
if (entry)
|
|
173
|
+
configObj.entry = entry;
|
|
174
|
+
if (assetsDirectory) {
|
|
175
|
+
configObj.assets = { directory: assetsDirectory };
|
|
176
|
+
if (notFoundStrategy) {
|
|
177
|
+
configObj.assets.notFoundStrategy =
|
|
178
|
+
notFoundStrategy;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
genConfig = toml.stringify(configObj);
|
|
187
182
|
}
|
|
188
183
|
if (fs.existsSync(newFilePath)) {
|
|
189
|
-
logger.error(
|
|
184
|
+
logger.error(`${path.basename(newFilePath)}` +
|
|
185
|
+
t('generate_config_error').d('already exists'));
|
|
190
186
|
return;
|
|
191
187
|
}
|
|
192
188
|
else {
|
|
@@ -0,0 +1,97 @@
|
|
|
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 { confirm as clackConfirm, isCancel, multiselect as clackMultiselect, select as clackSelect, text as clackText, cancel as clackCancel } from '@clack/prompts';
|
|
11
|
+
import multiLevelSelect from '../components/mutiLevelSelect.js';
|
|
12
|
+
function normalizeChoices(choices) {
|
|
13
|
+
if (!choices)
|
|
14
|
+
return undefined;
|
|
15
|
+
return choices.map((c) => {
|
|
16
|
+
if (typeof c === 'string')
|
|
17
|
+
return { label: c, value: c };
|
|
18
|
+
return { label: c.name, value: String(c.value), hint: c.hint };
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
export function promptParameter(param) {
|
|
22
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
23
|
+
var _a;
|
|
24
|
+
const { type, question, defaultValue, validate } = param;
|
|
25
|
+
let value = '';
|
|
26
|
+
const msg = question;
|
|
27
|
+
if (type === 'text') {
|
|
28
|
+
const v = yield clackText({
|
|
29
|
+
message: msg,
|
|
30
|
+
placeholder: typeof defaultValue === 'string' ? defaultValue : undefined,
|
|
31
|
+
initialValue: typeof defaultValue === 'string' ? defaultValue : undefined,
|
|
32
|
+
validate: validate
|
|
33
|
+
? (val) => {
|
|
34
|
+
if (val === undefined)
|
|
35
|
+
return 'Value is required';
|
|
36
|
+
const res = validate(val);
|
|
37
|
+
return res === true ? undefined : res;
|
|
38
|
+
}
|
|
39
|
+
: undefined
|
|
40
|
+
});
|
|
41
|
+
if (isCancel(v)) {
|
|
42
|
+
clackCancel('Operation cancelled.');
|
|
43
|
+
process.exit(130);
|
|
44
|
+
}
|
|
45
|
+
value = v;
|
|
46
|
+
}
|
|
47
|
+
else if (type === 'confirm') {
|
|
48
|
+
const v = yield clackConfirm({
|
|
49
|
+
message: msg,
|
|
50
|
+
initialValue: (_a = defaultValue) !== null && _a !== void 0 ? _a : false
|
|
51
|
+
});
|
|
52
|
+
if (isCancel(v)) {
|
|
53
|
+
clackCancel('Operation cancelled.');
|
|
54
|
+
process.exit(130);
|
|
55
|
+
}
|
|
56
|
+
value = v;
|
|
57
|
+
}
|
|
58
|
+
else if (type === 'select') {
|
|
59
|
+
const options = normalizeChoices(param.choices) || [];
|
|
60
|
+
const v = yield clackSelect({
|
|
61
|
+
message: msg,
|
|
62
|
+
options,
|
|
63
|
+
initialValue: defaultValue || undefined
|
|
64
|
+
});
|
|
65
|
+
if (isCancel(v)) {
|
|
66
|
+
clackCancel('Operation cancelled.');
|
|
67
|
+
process.exit(130);
|
|
68
|
+
}
|
|
69
|
+
value = v;
|
|
70
|
+
}
|
|
71
|
+
else if (type === 'multiselect') {
|
|
72
|
+
const options = normalizeChoices(param.choices) || [];
|
|
73
|
+
const initialValues = (defaultValue || []).map((v) => String(v));
|
|
74
|
+
const v = yield clackMultiselect({
|
|
75
|
+
message: msg,
|
|
76
|
+
options,
|
|
77
|
+
initialValues
|
|
78
|
+
});
|
|
79
|
+
if (isCancel(v)) {
|
|
80
|
+
clackCancel('Operation cancelled.');
|
|
81
|
+
process.exit(130);
|
|
82
|
+
}
|
|
83
|
+
value = v;
|
|
84
|
+
}
|
|
85
|
+
else if (type === 'multiLevelSelect') {
|
|
86
|
+
const items = (param.treeItems || []);
|
|
87
|
+
const v = yield multiLevelSelect(items, msg);
|
|
88
|
+
if (v === null) {
|
|
89
|
+
clackCancel('Operation cancelled.');
|
|
90
|
+
process.exit(130);
|
|
91
|
+
}
|
|
92
|
+
value = v;
|
|
93
|
+
}
|
|
94
|
+
return value;
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
export default promptParameter;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "esa-cli",
|
|
3
|
-
"version": "0.0.2-beta.
|
|
3
|
+
"version": "0.0.2-beta.15",
|
|
4
4
|
"description": "A CLI for operating Alibaba Cloud ESA EdgeRoutine (Edge Functions).",
|
|
5
5
|
"main": "bin/enter.cjs",
|
|
6
6
|
"type": "module",
|
|
@@ -72,6 +72,7 @@
|
|
|
72
72
|
"vitest": "^2.0.4"
|
|
73
73
|
},
|
|
74
74
|
"dependencies": {
|
|
75
|
+
"@clack/prompts": "1.0.0-alpha.4",
|
|
75
76
|
"@alicloud/esa20240910": "2.25.0",
|
|
76
77
|
"@alicloud/openapi-client": "^0.4.7",
|
|
77
78
|
"@babel/generator": "^7.26.3",
|
|
@@ -90,6 +91,7 @@
|
|
|
90
91
|
"esbuild-plugin-less": "^1.3.8",
|
|
91
92
|
"form-data": "^4.0.0",
|
|
92
93
|
"fs-extra": "^11.2.0",
|
|
94
|
+
"haikunator": "^2.1.2",
|
|
93
95
|
"http-proxy-agent": "^7.0.2",
|
|
94
96
|
"ink": "^5.0.1",
|
|
95
97
|
"ink-select-input": "^6.0.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
# ESLint 配置说明
|
|
2
|
-
|
|
3
|
-
本项目已配置ESLint来检查代码质量,包括以下功能:
|
|
4
|
-
|
|
5
|
-
## 已配置的检查规则
|
|
6
|
-
|
|
7
|
-
### 1. Import 排序检查
|
|
8
|
-
|
|
9
|
-
- **规则**: `import/order`
|
|
10
|
-
- **功能**: 自动排序import语句,按照以下顺序:
|
|
11
|
-
1. Node.js 内置模块 (如 `fs`, `path`)
|
|
12
|
-
2. 第三方模块 (如 `react`, `lodash`)
|
|
13
|
-
3. 内部模块 (项目内部文件)
|
|
14
|
-
4. 父级模块 (`../`)
|
|
15
|
-
5. 同级模块 (`./`)
|
|
16
|
-
6. 当前目录的 index 文件
|
|
17
|
-
- **格式**: 每组之间用空行分隔,按字母顺序排列
|
|
18
|
-
|
|
19
|
-
### 2. 引号检查
|
|
20
|
-
|
|
21
|
-
- **规则**: `quotes`, `@typescript-eslint/quotes`
|
|
22
|
-
- **功能**: 强制使用单引号
|
|
23
|
-
- **例外**: 允许在需要转义的情况下使用双引号,支持模板字符串
|
|
24
|
-
|
|
25
|
-
### 3. 多余变量检查
|
|
26
|
-
|
|
27
|
-
- **规则**: `@typescript-eslint/no-unused-vars`
|
|
28
|
-
- **功能**: 检查未使用的变量、参数和导入
|
|
29
|
-
- **例外**: 以 `_` 开头的变量会被忽略(如 `_unusedVariable`)
|
|
30
|
-
|
|
31
|
-
### 4. 其他检查
|
|
32
|
-
|
|
33
|
-
- **重复导入检查**: `import/no-duplicates`
|
|
34
|
-
- **未使用表达式检查**: `no-unused-expressions`
|
|
35
|
-
- **TypeScript类型检查**: 警告使用 `any` 类型
|
|
36
|
-
|
|
37
|
-
## 使用方法
|
|
38
|
-
|
|
39
|
-
### 检查代码
|
|
40
|
-
|
|
41
|
-
```bash
|
|
42
|
-
npm run eslint
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### 自动修复
|
|
46
|
-
|
|
47
|
-
```bash
|
|
48
|
-
npm run eslint -- --fix
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
### 检查特定文件
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
npx eslint src/commands/example.ts
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
## 配置说明
|
|
58
|
-
|
|
59
|
-
配置文件位于 `.eslintrc.cjs`,主要包含:
|
|
60
|
-
|
|
61
|
-
- **解析器**: `@typescript-eslint/parser` 用于解析TypeScript代码
|
|
62
|
-
- **插件**:
|
|
63
|
-
- `react` 和 `react-hooks` 用于React相关检查
|
|
64
|
-
- `import` 用于import相关检查
|
|
65
|
-
- `@typescript-eslint` 用于TypeScript特定检查
|
|
66
|
-
- **规则**: 详细的代码质量规则配置
|
|
67
|
-
- **设置**: TypeScript import解析器配置
|
|
68
|
-
|
|
69
|
-
## 注意事项
|
|
70
|
-
|
|
71
|
-
1. 如果遇到TypeScript版本警告,这是正常的,不影响功能
|
|
72
|
-
2. 未使用的变量请以 `_` 开头命名,这样ESLint会忽略它们
|
|
73
|
-
3. 自动修复功能可以解决大部分格式问题,但逻辑问题需要手动修复
|