@elysiumjs/core 0.4.3 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -17
- package/dist/app.d.ts +180 -0
- package/dist/cache.d.ts +113 -0
- package/dist/command.d.ts +272 -0
- package/dist/console.d.ts +166 -0
- package/dist/database.d.ts +112 -0
- package/dist/env.d.ts +33 -0
- package/dist/event.d.ts +93 -0
- package/dist/http.d.ts +246 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +19 -0
- package/dist/job.d.ts +105 -0
- package/dist/macros.d.ts +8 -0
- package/dist/middleware.d.ts +69 -0
- package/dist/model.d.ts +4802 -0
- package/dist/module.d.ts +44 -0
- package/dist/redis.d.ts +133 -0
- package/dist/repository.d.ts +163 -0
- package/dist/service.d.ts +131 -0
- package/dist/utils.d.ts +25 -0
- package/dist/wamp.d.ts +272 -0
- package/dist/websocket.d.ts +91 -0
- package/dist/worker.d.ts +219 -0
- package/package.json +16 -9
- package/tsconfig.json +34 -33
- package/index.ts +0 -54
- package/macros.ts +0 -16
- package/src/app.ts +0 -647
- package/src/cache.ts +0 -218
- package/src/command.ts +0 -908
- package/src/console.ts +0 -493
- package/src/database.ts +0 -257
- package/src/env.ts +0 -62
- package/src/event.ts +0 -227
- package/src/http.ts +0 -736
- package/src/job.ts +0 -196
- package/src/middleware.ts +0 -164
- package/src/model.ts +0 -386
- package/src/module.ts +0 -108
- package/src/redis.ts +0 -408
- package/src/repository.ts +0 -295
- package/src/service.ts +0 -351
- package/src/utils.ts +0 -95
- package/src/wamp.ts +0 -569
- package/src/websocket.ts +0 -191
- package/src/worker.ts +0 -849
- package/types.d.ts +0 -35
package/src/console.ts
DELETED
|
@@ -1,493 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2025-present Workbud Technologies Inc. All rights reserved.
|
|
2
|
-
//
|
|
3
|
-
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
// you may not use this file except in compliance with the License.
|
|
5
|
-
// You may obtain a copy of the License at
|
|
6
|
-
//
|
|
7
|
-
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
//
|
|
9
|
-
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
// See the License for the specific language governing permissions and
|
|
13
|
-
// limitations under the License.
|
|
14
|
-
|
|
15
|
-
import type { WriteStream } from 'node:tty';
|
|
16
|
-
|
|
17
|
-
import * as readline from 'node:readline';
|
|
18
|
-
|
|
19
|
-
import { isEmpty, omit } from 'radash';
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* ANSI color codes and styles for console output.
|
|
23
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
24
|
-
*/
|
|
25
|
-
export enum ConsoleFormat {
|
|
26
|
-
BLACK,
|
|
27
|
-
RED,
|
|
28
|
-
GREEN,
|
|
29
|
-
YELLOW,
|
|
30
|
-
BLUE,
|
|
31
|
-
MAGENTA,
|
|
32
|
-
CYAN,
|
|
33
|
-
WHITE,
|
|
34
|
-
GRAY,
|
|
35
|
-
BOLD,
|
|
36
|
-
UNDERLINE,
|
|
37
|
-
ITALIC,
|
|
38
|
-
INVERSE
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* A map of console format codes to ANSI escape codes.
|
|
43
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
44
|
-
*/
|
|
45
|
-
const formatMap: Record<ConsoleFormat, string> = {
|
|
46
|
-
[ConsoleFormat.BLACK]: Bun.color('black', 'ansi') || Bun.color('black', 'ansi-256') || '',
|
|
47
|
-
[ConsoleFormat.RED]: Bun.color('red', 'ansi') || Bun.color('red', 'ansi-256') || '',
|
|
48
|
-
[ConsoleFormat.GREEN]: Bun.color('green', 'ansi') || Bun.color('green', 'ansi-256') || '',
|
|
49
|
-
[ConsoleFormat.YELLOW]: Bun.color('yellow', 'ansi') || Bun.color('yellow', 'ansi-256') || '',
|
|
50
|
-
[ConsoleFormat.BLUE]: Bun.color('blue', 'ansi') || Bun.color('blue', 'ansi-256') || '',
|
|
51
|
-
[ConsoleFormat.MAGENTA]: Bun.color('magenta', 'ansi') || Bun.color('magenta', 'ansi-256') || '',
|
|
52
|
-
[ConsoleFormat.CYAN]: Bun.color('cyan', 'ansi') || Bun.color('cyan', 'ansi-256') || '',
|
|
53
|
-
[ConsoleFormat.WHITE]: Bun.color('white', 'ansi') || Bun.color('white', 'ansi-256') || '',
|
|
54
|
-
[ConsoleFormat.GRAY]: Bun.color('gray', 'ansi') || Bun.color('gray', 'ansi-256') || '',
|
|
55
|
-
[ConsoleFormat.BOLD]: '\x1b[1m',
|
|
56
|
-
[ConsoleFormat.UNDERLINE]: '\x1b[4m',
|
|
57
|
-
[ConsoleFormat.ITALIC]: '\x1b[3m',
|
|
58
|
-
[ConsoleFormat.INVERSE]: '\x1b[7m'
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* A utility class for console IO with various formatting options.
|
|
63
|
-
* @author Axel Nana <axel.nana@workbud.com>
|
|
64
|
-
*/
|
|
65
|
-
export class InteractsWithConsole {
|
|
66
|
-
protected static readonly SPACE_WIDTH = 60;
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Write a message to the console.
|
|
70
|
-
* @param message The message to write.
|
|
71
|
-
* @param newLine Whether to add a newline at the end (default: `true`).
|
|
72
|
-
* @param out The output stream to write to (default: `process.stdout`).
|
|
73
|
-
*/
|
|
74
|
-
public write(message: string, newLine: boolean = true, out: WriteStream = process.stdout): void {
|
|
75
|
-
out.write(message + (newLine ? '\n' : ''));
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Write a new line to the console.
|
|
80
|
-
*/
|
|
81
|
-
public newLine(): void {
|
|
82
|
-
this.write('\n', false);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Write an info message to the console (blue text).
|
|
87
|
-
* @param message The message to write.
|
|
88
|
-
*/
|
|
89
|
-
public info(message: string): void {
|
|
90
|
-
this.write(`ℹ️ ${message}`);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Write a success message to the console (green text).
|
|
95
|
-
* @param message The message to write.
|
|
96
|
-
*/
|
|
97
|
-
public success(message: string): void {
|
|
98
|
-
this.write(`✅ ${message}`);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Write a warning message to the console (yellow text).
|
|
103
|
-
* @param message The message to write.
|
|
104
|
-
*/
|
|
105
|
-
public warning(message: string): void {
|
|
106
|
-
this.write(`⚠️ ${message}`);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Write an error message to the console (red text).
|
|
111
|
-
* @param message The message to write.
|
|
112
|
-
*/
|
|
113
|
-
public error(message: string): void {
|
|
114
|
-
this.write(`❌ ${message}`, true, process.stderr);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Write a debug message to the console (gray text).
|
|
119
|
-
* Only shown if the DEBUG environment variable is set.
|
|
120
|
-
* @param message The message to write.
|
|
121
|
-
*/
|
|
122
|
-
public debug(message: string): void {
|
|
123
|
-
if (process.env.DEBUG) {
|
|
124
|
-
this.write(`🔍 ${message}`);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Display a JavaScript error in the console with its message, stack trace,
|
|
130
|
-
* and any additional relevant information.
|
|
131
|
-
* @param error The error to display.
|
|
132
|
-
* @param title Optional title to display before the error message (default: '').
|
|
133
|
-
*/
|
|
134
|
-
public trace(error: Error & Record<string, any>, title?: string): void {
|
|
135
|
-
if (!error) return;
|
|
136
|
-
|
|
137
|
-
// Determine standard error information
|
|
138
|
-
const errorName = error.name || 'Error';
|
|
139
|
-
const errorMessage = error.message || 'An error occurred';
|
|
140
|
-
const errorStack = error.stack || '';
|
|
141
|
-
|
|
142
|
-
// Display the title if provided
|
|
143
|
-
if (title) {
|
|
144
|
-
this.title(title);
|
|
145
|
-
} else {
|
|
146
|
-
this.newLine();
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Display the error name and message in red
|
|
150
|
-
this.write(this.format(`${errorName}: ${errorMessage}`, ConsoleFormat.RED));
|
|
151
|
-
|
|
152
|
-
if (error.stack) {
|
|
153
|
-
// Display the stack trace in gray, each line prefixed by a tab for readability
|
|
154
|
-
this.write(this.format('Stack Trace:', ConsoleFormat.BOLD));
|
|
155
|
-
this.write(
|
|
156
|
-
this.format(
|
|
157
|
-
errorStack
|
|
158
|
-
.split('\n')
|
|
159
|
-
.map((line) => `\t${line}`)
|
|
160
|
-
.join('\n'),
|
|
161
|
-
ConsoleFormat.GRAY
|
|
162
|
-
)
|
|
163
|
-
);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// Display any other custom properties
|
|
167
|
-
const customProps = omit(error, ['name', 'message', 'stack']);
|
|
168
|
-
|
|
169
|
-
if (!isEmpty(customProps)) {
|
|
170
|
-
this.write(this.format('Additional Information:', ConsoleFormat.BOLD));
|
|
171
|
-
Object.keys(customProps).forEach((prop) => {
|
|
172
|
-
const value = error[prop];
|
|
173
|
-
this.write(`\t${prop}: ${JSON.stringify(value)}`);
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
this.newLine();
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Write a title to the console (bold text with underline).
|
|
182
|
-
* @param title The title to write.
|
|
183
|
-
*/
|
|
184
|
-
public title(title: string): void {
|
|
185
|
-
this.newLine();
|
|
186
|
-
this.write(this.format(title, ConsoleFormat.BOLD, ConsoleFormat.UNDERLINE));
|
|
187
|
-
this.newLine();
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Write a section header to the console (bold text).
|
|
192
|
-
* @param header The section header to write.
|
|
193
|
-
*/
|
|
194
|
-
public section(header: string): void {
|
|
195
|
-
this.newLine();
|
|
196
|
-
this.write(`\x1b[1m${header}\x1b[0m`);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Create a table from an array of objects and write it to the console.
|
|
201
|
-
* @param data The array of objects to display.
|
|
202
|
-
* @param columns Optional column configuration.
|
|
203
|
-
*/
|
|
204
|
-
public table<T extends Record<string, any>>(
|
|
205
|
-
data: T[],
|
|
206
|
-
columns?: {
|
|
207
|
-
[K in keyof T]?: {
|
|
208
|
-
header?: string;
|
|
209
|
-
width?: number;
|
|
210
|
-
format?: (value: T[K]) => string;
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
): void {
|
|
214
|
-
if (data.length === 0) {
|
|
215
|
-
this.info('No data to display');
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// Determine columns to display
|
|
220
|
-
const keys = Object.keys(columns || data[0]) as (keyof T)[];
|
|
221
|
-
|
|
222
|
-
// Calculate column widths
|
|
223
|
-
const widths: Record<string, number> = {};
|
|
224
|
-
for (const key of keys) {
|
|
225
|
-
const columnConfig = columns?.[key];
|
|
226
|
-
if (columnConfig?.width) {
|
|
227
|
-
widths[key as string] = columnConfig.width;
|
|
228
|
-
continue;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// Get header length
|
|
232
|
-
const headerLength = (columnConfig?.header || String(key)).length;
|
|
233
|
-
|
|
234
|
-
// Get max data length
|
|
235
|
-
const maxDataLength = Math.max(
|
|
236
|
-
...data.map((row) => {
|
|
237
|
-
const value = row[key];
|
|
238
|
-
if (columnConfig?.format) {
|
|
239
|
-
return columnConfig.format(value).length;
|
|
240
|
-
}
|
|
241
|
-
return String(value === null || value === undefined ? '' : value).length;
|
|
242
|
-
})
|
|
243
|
-
);
|
|
244
|
-
|
|
245
|
-
widths[key as string] = Math.max(headerLength, maxDataLength);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// Create header row
|
|
249
|
-
let header = '';
|
|
250
|
-
let separator = '';
|
|
251
|
-
for (const key of keys) {
|
|
252
|
-
const columnConfig = columns?.[key];
|
|
253
|
-
const headerText = columnConfig?.header || String(key);
|
|
254
|
-
const width = widths[key as string];
|
|
255
|
-
|
|
256
|
-
header += `| ${headerText.padEnd(width)} `;
|
|
257
|
-
separator += `| ${'-'.repeat(width)} `;
|
|
258
|
-
}
|
|
259
|
-
header += '|';
|
|
260
|
-
separator += '|';
|
|
261
|
-
|
|
262
|
-
this.write(header);
|
|
263
|
-
this.write(separator);
|
|
264
|
-
|
|
265
|
-
// Create data rows
|
|
266
|
-
for (const row of data) {
|
|
267
|
-
let line = '';
|
|
268
|
-
for (const key of keys) {
|
|
269
|
-
const columnConfig = columns?.[key];
|
|
270
|
-
const width = widths[key as string];
|
|
271
|
-
const value = row[key];
|
|
272
|
-
|
|
273
|
-
let displayValue: string;
|
|
274
|
-
if (columnConfig?.format) {
|
|
275
|
-
displayValue = columnConfig.format(value);
|
|
276
|
-
} else {
|
|
277
|
-
displayValue = String(value === null || value === undefined ? '' : value);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
line += `| ${displayValue.padEnd(width)} `;
|
|
281
|
-
}
|
|
282
|
-
line += '|';
|
|
283
|
-
this.write(line);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
this.newLine();
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
/**
|
|
290
|
-
* Format text with multiple ANSI styles.
|
|
291
|
-
* @param text The text to format.
|
|
292
|
-
* @param styles The styles to apply.
|
|
293
|
-
* @returns The formatted text.
|
|
294
|
-
*/
|
|
295
|
-
public format(text: string, ...styles: ConsoleFormat[]): string {
|
|
296
|
-
const styleCodes = styles.map((style) => formatMap[style]).join('');
|
|
297
|
-
return `${styleCodes}${text}\x1b[0m`;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* Format text as bold.
|
|
302
|
-
* @param text The text to format.
|
|
303
|
-
* @returns The formatted text.
|
|
304
|
-
*/
|
|
305
|
-
public bold(text: string): string {
|
|
306
|
-
return this.format(text, ConsoleFormat.BOLD);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
/**
|
|
310
|
-
* Format text as italic.
|
|
311
|
-
* @param text The text to format.
|
|
312
|
-
* @returns The formatted text.
|
|
313
|
-
*/
|
|
314
|
-
public italic(text: string): string {
|
|
315
|
-
return this.format(text, ConsoleFormat.ITALIC);
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
/**
|
|
319
|
-
* Format text as underline.
|
|
320
|
-
* @param text The text to format.
|
|
321
|
-
* @returns The formatted text.
|
|
322
|
-
*/
|
|
323
|
-
public underline(text: string): string {
|
|
324
|
-
return this.format(text, ConsoleFormat.UNDERLINE);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
/**
|
|
328
|
-
* Clear the console screen.
|
|
329
|
-
*/
|
|
330
|
-
public clear(): void {
|
|
331
|
-
process.stdout.write('\x1Bc');
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
/**
|
|
335
|
-
* Move the cursor to a specific position.
|
|
336
|
-
* @param x The x coordinate (column).
|
|
337
|
-
* @param y The y coordinate (row).
|
|
338
|
-
*/
|
|
339
|
-
public moveCursor(x: number, y: number): void {
|
|
340
|
-
process.stdout.moveCursor(x, y);
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
/**
|
|
344
|
-
* Clear the current line in the console.
|
|
345
|
-
*/
|
|
346
|
-
public clearLine(): void {
|
|
347
|
-
process.stdout.clearLine(0);
|
|
348
|
-
process.stdout.cursorTo(0);
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// User Input Methods
|
|
352
|
-
|
|
353
|
-
/**
|
|
354
|
-
* Prompt the user for input.
|
|
355
|
-
* @param question The question to ask.
|
|
356
|
-
* @param defaultValue Optional default value.
|
|
357
|
-
* @returns The user's input.
|
|
358
|
-
*/
|
|
359
|
-
protected async prompt(question: string, defaultValue?: string): Promise<string> {
|
|
360
|
-
const rl = readline.createInterface({
|
|
361
|
-
input: process.stdin,
|
|
362
|
-
output: process.stdout
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
const defaultText = defaultValue ? ` (default: ${defaultValue})` : '';
|
|
366
|
-
|
|
367
|
-
return new Promise<string>((resolve) => {
|
|
368
|
-
rl.question(`${question}${defaultText}: `, (answer) => {
|
|
369
|
-
rl.close();
|
|
370
|
-
resolve(answer || defaultValue || '');
|
|
371
|
-
});
|
|
372
|
-
});
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
/**
|
|
376
|
-
* Prompt the user for a password (input is hidden).
|
|
377
|
-
* @param question The question to ask.
|
|
378
|
-
* @returns The user's password.
|
|
379
|
-
*/
|
|
380
|
-
protected async promptPassword(question: string): Promise<string> {
|
|
381
|
-
// Create readline interface
|
|
382
|
-
const rl = readline.createInterface({
|
|
383
|
-
input: process.stdin,
|
|
384
|
-
output: process.stdout
|
|
385
|
-
});
|
|
386
|
-
|
|
387
|
-
// Mute stdin echo
|
|
388
|
-
process.stdin.setRawMode?.(true);
|
|
389
|
-
|
|
390
|
-
return new Promise<string>((resolve) => {
|
|
391
|
-
let password = '';
|
|
392
|
-
|
|
393
|
-
// Write question
|
|
394
|
-
process.stdout.write(`${question}: `);
|
|
395
|
-
|
|
396
|
-
// Handle keypress events
|
|
397
|
-
process.stdin.on('data', (data) => {
|
|
398
|
-
const char = data.toString();
|
|
399
|
-
|
|
400
|
-
// Check for Enter key (carriage return)
|
|
401
|
-
if (char === '\r' || char === '\n') {
|
|
402
|
-
process.stdout.write('\n');
|
|
403
|
-
process.stdin.setRawMode?.(false);
|
|
404
|
-
process.stdin.removeAllListeners('data');
|
|
405
|
-
rl.close();
|
|
406
|
-
resolve(password);
|
|
407
|
-
return;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// Check for backspace
|
|
411
|
-
if (char === '\b' || char === '\x7f') {
|
|
412
|
-
if (password.length > 0) {
|
|
413
|
-
password = password.slice(0, -1);
|
|
414
|
-
process.stdout.write('\b \b'); // Erase character from terminal
|
|
415
|
-
}
|
|
416
|
-
return;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
// Add character to password
|
|
420
|
-
password += char;
|
|
421
|
-
process.stdout.write('*'); // Show asterisk instead of actual character
|
|
422
|
-
});
|
|
423
|
-
});
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
/**
|
|
427
|
-
* Prompt the user for confirmation (yes/no).
|
|
428
|
-
* @param question The question to ask.
|
|
429
|
-
* @param defaultValue Optional default value (true for yes, false for no).
|
|
430
|
-
* @returns True if the user confirmed, false otherwise.
|
|
431
|
-
*/
|
|
432
|
-
protected async confirm(question: string, defaultValue: boolean = false): Promise<boolean> {
|
|
433
|
-
const defaultText = defaultValue ? 'Y/n' : 'y/N';
|
|
434
|
-
const answer = await this.prompt(`${question} [${defaultText}]`);
|
|
435
|
-
|
|
436
|
-
if (!answer) {
|
|
437
|
-
return defaultValue;
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
return answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes';
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
/**
|
|
444
|
-
* Prompt the user to select from a list of options.
|
|
445
|
-
* @param question The question to ask.
|
|
446
|
-
* @param options The options to choose from.
|
|
447
|
-
* @param defaultIndex Optional default option index.
|
|
448
|
-
* @returns The selected option.
|
|
449
|
-
*/
|
|
450
|
-
protected async select<T extends string>(
|
|
451
|
-
question: string,
|
|
452
|
-
options: T[],
|
|
453
|
-
defaultIndex: number = 0
|
|
454
|
-
): Promise<T> {
|
|
455
|
-
if (options.length === 0) {
|
|
456
|
-
throw new Error('No options provided for selection');
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
// Display options
|
|
460
|
-
this.write(question);
|
|
461
|
-
options.forEach((option, index) => {
|
|
462
|
-
const isDefault = index === defaultIndex;
|
|
463
|
-
this.write(` ${index + 1}. ${option}${isDefault ? ' (default)' : ''}`);
|
|
464
|
-
});
|
|
465
|
-
|
|
466
|
-
// Get user selection
|
|
467
|
-
const selection = await this.prompt('Enter your choice (number)');
|
|
468
|
-
|
|
469
|
-
// Parse selection
|
|
470
|
-
if (!selection) {
|
|
471
|
-
return options[defaultIndex];
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
const index = parseInt(selection, 10) - 1;
|
|
475
|
-
if (isNaN(index) || index < 0 || index >= options.length) {
|
|
476
|
-
this.warning(`Invalid selection. Using default: ${options[defaultIndex]}`);
|
|
477
|
-
return options[defaultIndex];
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
return options[index];
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
/**
|
|
484
|
-
* Format a time value in seconds to a human-readable string.
|
|
485
|
-
* @param seconds The time value in seconds.
|
|
486
|
-
* @returns A formatted time string.
|
|
487
|
-
*/
|
|
488
|
-
protected formatTime(seconds: number): string {
|
|
489
|
-
if (seconds < 60) return `${seconds.toFixed(1)}s`;
|
|
490
|
-
if (seconds < 3600) return `${Math.floor(seconds / 60)}m ${Math.floor(seconds % 60)}s`;
|
|
491
|
-
return `${Math.floor(seconds / 3600)}h ${Math.floor((seconds % 3600) / 60)}m`;
|
|
492
|
-
}
|
|
493
|
-
}
|