mepcli 0.2.1 → 0.2.5
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 +61 -17
- package/dist/ansi.d.ts +2 -0
- package/dist/ansi.js +2 -0
- package/dist/base.d.ts +44 -0
- package/dist/base.js +87 -0
- package/dist/core.d.ts +6 -1
- package/dist/core.js +35 -775
- package/dist/prompts/checkbox.d.ts +10 -0
- package/dist/prompts/checkbox.js +92 -0
- package/dist/prompts/confirm.d.ts +7 -0
- package/dist/prompts/confirm.js +40 -0
- package/dist/prompts/date.d.ts +10 -0
- package/dist/prompts/date.js +157 -0
- package/dist/prompts/file.d.ts +13 -0
- package/dist/prompts/file.js +194 -0
- package/dist/prompts/list.d.ts +9 -0
- package/dist/prompts/list.js +83 -0
- package/dist/prompts/multi-select.d.ts +14 -0
- package/dist/prompts/multi-select.js +149 -0
- package/dist/prompts/number.d.ts +10 -0
- package/dist/prompts/number.js +137 -0
- package/dist/prompts/select.d.ts +16 -0
- package/dist/prompts/select.js +162 -0
- package/dist/prompts/slider.d.ts +7 -0
- package/dist/prompts/slider.js +48 -0
- package/dist/prompts/text.d.ts +12 -0
- package/dist/prompts/text.js +245 -0
- package/dist/prompts/toggle.d.ts +7 -0
- package/dist/prompts/toggle.js +45 -0
- package/dist/theme.d.ts +2 -0
- package/dist/theme.js +11 -0
- package/dist/types.d.ts +24 -0
- package/example.ts +57 -5
- package/package.json +1 -1
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TextPrompt = void 0;
|
|
4
|
+
const ansi_1 = require("../ansi");
|
|
5
|
+
const base_1 = require("../base");
|
|
6
|
+
const theme_1 = require("../theme");
|
|
7
|
+
// --- Implementation: Text Prompt ---
|
|
8
|
+
class TextPrompt extends base_1.Prompt {
|
|
9
|
+
constructor(options) {
|
|
10
|
+
super(options);
|
|
11
|
+
this.errorMsg = '';
|
|
12
|
+
this.cursor = 0;
|
|
13
|
+
this.hasTyped = false;
|
|
14
|
+
this.renderLines = 1;
|
|
15
|
+
this.value = options.initial || '';
|
|
16
|
+
this.cursor = this.value.length;
|
|
17
|
+
}
|
|
18
|
+
render(firstRender) {
|
|
19
|
+
// TextPrompt needs the cursor visible!
|
|
20
|
+
this.print(ansi_1.ANSI.SHOW_CURSOR);
|
|
21
|
+
if (!firstRender) {
|
|
22
|
+
// Clear previous lines
|
|
23
|
+
for (let i = 0; i < this.renderLines; i++) {
|
|
24
|
+
this.print(ansi_1.ANSI.ERASE_LINE);
|
|
25
|
+
if (i < this.renderLines - 1)
|
|
26
|
+
this.print(ansi_1.ANSI.UP);
|
|
27
|
+
}
|
|
28
|
+
this.print(ansi_1.ANSI.CURSOR_LEFT);
|
|
29
|
+
}
|
|
30
|
+
let output = '';
|
|
31
|
+
// 1. Render the Prompt Message
|
|
32
|
+
const icon = this.errorMsg ? `${theme_1.theme.error}✖` : `${theme_1.theme.success}?`;
|
|
33
|
+
const multilineHint = this.options.multiline ? ` ${theme_1.theme.muted}(Press Ctrl+D to submit)${ansi_1.ANSI.RESET}` : '';
|
|
34
|
+
output += `${icon} ${ansi_1.ANSI.BOLD}${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET}${multilineHint} `;
|
|
35
|
+
// 2. Render the Value or Placeholder
|
|
36
|
+
let displayValue = '';
|
|
37
|
+
if (!this.value && this.options.placeholder && !this.errorMsg && !this.hasTyped) {
|
|
38
|
+
displayValue = `${theme_1.theme.muted}${this.options.placeholder}${ansi_1.ANSI.RESET}`;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
displayValue = this.options.isPassword ? '*'.repeat(this.value.length) : this.value;
|
|
42
|
+
displayValue = `${theme_1.theme.main}${displayValue}${ansi_1.ANSI.RESET}`;
|
|
43
|
+
}
|
|
44
|
+
output += displayValue;
|
|
45
|
+
// 3. Handle Error Message
|
|
46
|
+
if (this.errorMsg) {
|
|
47
|
+
output += `\n${theme_1.theme.error}>> ${this.errorMsg}${ansi_1.ANSI.RESET}`;
|
|
48
|
+
}
|
|
49
|
+
this.print(output);
|
|
50
|
+
// 4. Calculate Visual Metrics for Wrapping
|
|
51
|
+
const cols = process.stdout.columns || 80;
|
|
52
|
+
const stripAnsi = (str) => str.replace(/\x1b\[[0-9;]*m/g, '');
|
|
53
|
+
// Prompt String (visual part before value)
|
|
54
|
+
const promptStr = `${icon} ${theme_1.theme.title}${this.options.message} ${multilineHint} `;
|
|
55
|
+
const promptVisualLen = stripAnsi(promptStr).length;
|
|
56
|
+
// Value String (visual part)
|
|
57
|
+
const rawValue = (!this.value && this.options.placeholder && !this.errorMsg && !this.hasTyped)
|
|
58
|
+
? this.options.placeholder || ''
|
|
59
|
+
: (this.options.isPassword ? '*'.repeat(this.value.length) : this.value);
|
|
60
|
+
// Error String (visual part)
|
|
61
|
+
const errorVisualLines = this.errorMsg ? Math.ceil((3 + this.errorMsg.length) / cols) : 0;
|
|
62
|
+
// Calculate Total Lines and Cursor Position
|
|
63
|
+
// We simulate printing the prompt + value + error
|
|
64
|
+
let currentVisualLine = 0;
|
|
65
|
+
let currentCol = 0;
|
|
66
|
+
// State tracking for cursor
|
|
67
|
+
let cursorRow = 0;
|
|
68
|
+
let cursorCol = 0;
|
|
69
|
+
// Add Prompt
|
|
70
|
+
currentCol += promptVisualLen;
|
|
71
|
+
while (currentCol >= cols) {
|
|
72
|
+
currentVisualLine++;
|
|
73
|
+
currentCol -= cols;
|
|
74
|
+
}
|
|
75
|
+
// Add Value (Character by character to handle wrapping and cursor tracking accurately)
|
|
76
|
+
const valueLen = rawValue.length;
|
|
77
|
+
// If placeholder, we treat it as value for render height, but cursor is at 0
|
|
78
|
+
const isPlaceholder = (!this.value && this.options.placeholder && !this.errorMsg && !this.hasTyped);
|
|
79
|
+
for (let i = 0; i < valueLen; i++) {
|
|
80
|
+
// Check if we are at cursor position
|
|
81
|
+
if (!isPlaceholder && i === this.cursor) {
|
|
82
|
+
cursorRow = currentVisualLine;
|
|
83
|
+
cursorCol = currentCol;
|
|
84
|
+
}
|
|
85
|
+
const char = rawValue[i];
|
|
86
|
+
if (char === '\n') {
|
|
87
|
+
currentVisualLine++;
|
|
88
|
+
currentCol = 0;
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
currentCol++;
|
|
92
|
+
if (currentCol >= cols) {
|
|
93
|
+
currentVisualLine++;
|
|
94
|
+
currentCol = 0;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// If cursor is at the very end
|
|
99
|
+
if (!isPlaceholder && this.cursor === valueLen) {
|
|
100
|
+
cursorRow = currentVisualLine;
|
|
101
|
+
cursorCol = currentCol;
|
|
102
|
+
}
|
|
103
|
+
// If placeholder, cursor is at start of value
|
|
104
|
+
if (isPlaceholder) {
|
|
105
|
+
let pCol = promptVisualLen;
|
|
106
|
+
let pRow = 0;
|
|
107
|
+
while (pCol >= cols) {
|
|
108
|
+
pRow++;
|
|
109
|
+
pCol -= cols;
|
|
110
|
+
}
|
|
111
|
+
cursorRow = pRow;
|
|
112
|
+
cursorCol = pCol;
|
|
113
|
+
}
|
|
114
|
+
// Final height
|
|
115
|
+
const totalValueRows = currentVisualLine + 1;
|
|
116
|
+
this.renderLines = totalValueRows + errorVisualLines;
|
|
117
|
+
// 5. Position Cursor Logic
|
|
118
|
+
const endRow = this.renderLines - 1;
|
|
119
|
+
// Move up to cursor row
|
|
120
|
+
const linesUp = endRow - cursorRow;
|
|
121
|
+
if (linesUp > 0) {
|
|
122
|
+
this.print(`\x1b[${linesUp}A`);
|
|
123
|
+
}
|
|
124
|
+
// Move to cursor col
|
|
125
|
+
this.print(ansi_1.ANSI.CURSOR_LEFT); // Go to col 0
|
|
126
|
+
if (cursorCol > 0) {
|
|
127
|
+
this.print(`\x1b[${cursorCol}C`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
handleInput(char) {
|
|
131
|
+
// Enter
|
|
132
|
+
if (char === '\r' || char === '\n') {
|
|
133
|
+
if (this.options.multiline) {
|
|
134
|
+
this.value = this.value.slice(0, this.cursor) + '\n' + this.value.slice(this.cursor);
|
|
135
|
+
this.cursor++;
|
|
136
|
+
this.render(false);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
this.validateAndSubmit();
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
// Ctrl+D (EOF) or Ctrl+S for Submit in Multiline
|
|
143
|
+
if (this.options.multiline && (char === '\u0004' || char === '\u0013')) {
|
|
144
|
+
this.validateAndSubmit();
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
// Backspace
|
|
148
|
+
if (char === '\u0008' || char === '\x7f') {
|
|
149
|
+
this.hasTyped = true;
|
|
150
|
+
if (this.cursor > 0) {
|
|
151
|
+
this.value = this.value.slice(0, this.cursor - 1) + this.value.slice(this.cursor);
|
|
152
|
+
this.cursor--;
|
|
153
|
+
this.errorMsg = '';
|
|
154
|
+
this.render(false);
|
|
155
|
+
}
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
// Arrow Left
|
|
159
|
+
if (this.isLeft(char)) {
|
|
160
|
+
if (this.cursor > 0) {
|
|
161
|
+
this.cursor--;
|
|
162
|
+
this.render(false);
|
|
163
|
+
}
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
// Arrow Right
|
|
167
|
+
if (this.isRight(char)) {
|
|
168
|
+
if (this.cursor < this.value.length) {
|
|
169
|
+
this.cursor++;
|
|
170
|
+
this.render(false);
|
|
171
|
+
}
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
// Delete key
|
|
175
|
+
if (char === '\u001b[3~') {
|
|
176
|
+
this.hasTyped = true;
|
|
177
|
+
if (this.cursor < this.value.length) {
|
|
178
|
+
this.value = this.value.slice(0, this.cursor) + this.value.slice(this.cursor + 1);
|
|
179
|
+
this.errorMsg = '';
|
|
180
|
+
this.render(false);
|
|
181
|
+
}
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
// Regular Typing & Paste
|
|
185
|
+
if (!/^[\x00-\x1F]/.test(char) && !char.startsWith('\x1b')) {
|
|
186
|
+
this.hasTyped = true;
|
|
187
|
+
this.value = this.value.slice(0, this.cursor) + char + this.value.slice(this.cursor);
|
|
188
|
+
this.cursor += char.length;
|
|
189
|
+
this.errorMsg = '';
|
|
190
|
+
this.render(false);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
validateAndSubmit() {
|
|
194
|
+
if (this.options.validate) {
|
|
195
|
+
const result = this.options.validate(this.value);
|
|
196
|
+
// Handle Promise validation
|
|
197
|
+
if (result instanceof Promise) {
|
|
198
|
+
// Show loading state
|
|
199
|
+
this.print(`\n${ansi_1.ANSI.ERASE_LINE}${theme_1.theme.main}Validating...${ansi_1.ANSI.RESET}`);
|
|
200
|
+
this.print(ansi_1.ANSI.UP);
|
|
201
|
+
result.then(valid => {
|
|
202
|
+
// Clear loading message
|
|
203
|
+
this.print(`\n${ansi_1.ANSI.ERASE_LINE}`);
|
|
204
|
+
this.print(ansi_1.ANSI.UP);
|
|
205
|
+
if (typeof valid === 'string' && valid.length > 0) {
|
|
206
|
+
this.errorMsg = valid;
|
|
207
|
+
this.render(false);
|
|
208
|
+
}
|
|
209
|
+
else if (valid === false) {
|
|
210
|
+
this.errorMsg = 'Invalid input';
|
|
211
|
+
this.render(false);
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
if (this.errorMsg) {
|
|
215
|
+
this.print(`\n${ansi_1.ANSI.ERASE_LINE}${ansi_1.ANSI.UP}`);
|
|
216
|
+
}
|
|
217
|
+
this.submit(this.value);
|
|
218
|
+
}
|
|
219
|
+
}).catch(err => {
|
|
220
|
+
this.print(`\n${ansi_1.ANSI.ERASE_LINE}`);
|
|
221
|
+
this.print(ansi_1.ANSI.UP);
|
|
222
|
+
this.errorMsg = err.message || 'Validation failed';
|
|
223
|
+
this.render(false);
|
|
224
|
+
});
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
// Handle Sync validation
|
|
228
|
+
if (typeof result === 'string' && result.length > 0) {
|
|
229
|
+
this.errorMsg = result;
|
|
230
|
+
this.render(false);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
if (result === false) {
|
|
234
|
+
this.errorMsg = 'Invalid input';
|
|
235
|
+
this.render(false);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
if (this.errorMsg) {
|
|
240
|
+
this.print(`\n${ansi_1.ANSI.ERASE_LINE}${ansi_1.ANSI.UP}`);
|
|
241
|
+
}
|
|
242
|
+
this.submit(this.value);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
exports.TextPrompt = TextPrompt;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Prompt } from '../base';
|
|
2
|
+
import { ToggleOptions } from '../types';
|
|
3
|
+
export declare class TogglePrompt extends Prompt<boolean, ToggleOptions> {
|
|
4
|
+
constructor(options: ToggleOptions);
|
|
5
|
+
protected render(firstRender: boolean): void;
|
|
6
|
+
protected handleInput(char: string): void;
|
|
7
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TogglePrompt = void 0;
|
|
4
|
+
const ansi_1 = require("../ansi");
|
|
5
|
+
const base_1 = require("../base");
|
|
6
|
+
const theme_1 = require("../theme");
|
|
7
|
+
// --- Implementation: Toggle Prompt ---
|
|
8
|
+
class TogglePrompt extends base_1.Prompt {
|
|
9
|
+
constructor(options) {
|
|
10
|
+
super(options);
|
|
11
|
+
this.value = options.initial ?? false;
|
|
12
|
+
}
|
|
13
|
+
render(firstRender) {
|
|
14
|
+
this.print(ansi_1.ANSI.HIDE_CURSOR);
|
|
15
|
+
if (!firstRender) {
|
|
16
|
+
this.print(`${ansi_1.ANSI.ERASE_LINE}${ansi_1.ANSI.CURSOR_LEFT}`);
|
|
17
|
+
}
|
|
18
|
+
const activeText = this.options.activeText || 'ON';
|
|
19
|
+
const inactiveText = this.options.inactiveText || 'OFF';
|
|
20
|
+
let toggleDisplay = '';
|
|
21
|
+
if (this.value) {
|
|
22
|
+
toggleDisplay = `${theme_1.theme.main}[${ansi_1.ANSI.BOLD}${activeText}${ansi_1.ANSI.RESET}${theme_1.theme.main}]${ansi_1.ANSI.RESET} ${theme_1.theme.muted}${inactiveText}${ansi_1.ANSI.RESET}`;
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
toggleDisplay = `${theme_1.theme.muted}${activeText}${ansi_1.ANSI.RESET} ${theme_1.theme.main}[${ansi_1.ANSI.BOLD}${inactiveText}${ansi_1.ANSI.RESET}${theme_1.theme.main}]${ansi_1.ANSI.RESET}`;
|
|
26
|
+
}
|
|
27
|
+
this.print(`${theme_1.theme.success}?${ansi_1.ANSI.RESET} ${ansi_1.ANSI.BOLD}${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET} ${toggleDisplay}`);
|
|
28
|
+
this.print(`\x1b[${toggleDisplay.length}D`); // Move back is not really needed as we hide cursor, but kept for consistency
|
|
29
|
+
}
|
|
30
|
+
handleInput(char) {
|
|
31
|
+
if (char === '\r' || char === '\n') {
|
|
32
|
+
this.submit(this.value);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (this.isLeft(char) || this.isRight(char) || char === 'h' || char === 'l') { // Left/Right
|
|
36
|
+
this.value = !this.value;
|
|
37
|
+
this.render(false);
|
|
38
|
+
}
|
|
39
|
+
if (char === ' ') {
|
|
40
|
+
this.value = !this.value;
|
|
41
|
+
this.render(false);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.TogglePrompt = TogglePrompt;
|
package/dist/theme.d.ts
ADDED
package/dist/theme.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.theme = void 0;
|
|
4
|
+
const ansi_1 = require("./ansi");
|
|
5
|
+
exports.theme = {
|
|
6
|
+
main: ansi_1.ANSI.FG_CYAN,
|
|
7
|
+
success: ansi_1.ANSI.FG_GREEN,
|
|
8
|
+
error: ansi_1.ANSI.FG_RED,
|
|
9
|
+
muted: ansi_1.ANSI.FG_GRAY,
|
|
10
|
+
title: ansi_1.ANSI.RESET
|
|
11
|
+
};
|
package/dist/types.d.ts
CHANGED
|
@@ -53,3 +53,27 @@ export interface ToggleOptions extends BaseOptions {
|
|
|
53
53
|
activeText?: string;
|
|
54
54
|
inactiveText?: string;
|
|
55
55
|
}
|
|
56
|
+
export interface ListOptions extends BaseOptions {
|
|
57
|
+
placeholder?: string;
|
|
58
|
+
initial?: string[];
|
|
59
|
+
validate?: (value: string[]) => string | boolean | Promise<string | boolean>;
|
|
60
|
+
}
|
|
61
|
+
export interface SliderOptions extends BaseOptions {
|
|
62
|
+
min: number;
|
|
63
|
+
max: number;
|
|
64
|
+
initial?: number;
|
|
65
|
+
step?: number;
|
|
66
|
+
unit?: string;
|
|
67
|
+
}
|
|
68
|
+
export interface DateOptions extends BaseOptions {
|
|
69
|
+
initial?: Date;
|
|
70
|
+
min?: Date;
|
|
71
|
+
max?: Date;
|
|
72
|
+
}
|
|
73
|
+
export interface FileOptions extends BaseOptions {
|
|
74
|
+
basePath?: string;
|
|
75
|
+
extensions?: string[];
|
|
76
|
+
onlyDirectories?: boolean;
|
|
77
|
+
}
|
|
78
|
+
export interface MultiSelectOptions extends CheckboxOptions {
|
|
79
|
+
}
|
package/example.ts
CHANGED
|
@@ -3,11 +3,12 @@ import { MepCLI } from './src'; // Or 'mepcli' if installed via NPM
|
|
|
3
3
|
/**
|
|
4
4
|
* Runs a comprehensive demo showcasing all MepCLI prompt types and utilities.
|
|
5
5
|
* This demonstrates all core functionalities including Text, Password, Select,
|
|
6
|
-
* Checkbox, Number, Toggle, Confirm,
|
|
6
|
+
* Checkbox, Number, Toggle, Confirm, List, Slider, Date, File, MultiSelect,
|
|
7
|
+
* and the Spin utility.
|
|
7
8
|
*/
|
|
8
9
|
async function runComprehensiveDemo() {
|
|
9
10
|
console.clear();
|
|
10
|
-
console.log("--- MepCLI Comprehensive Demo (All
|
|
11
|
+
console.log("--- MepCLI Comprehensive Demo (All 12 Prompts + Spin Utility) ---\n");
|
|
11
12
|
|
|
12
13
|
try {
|
|
13
14
|
// --- 1. Text Prompt (Input with Validation and initial value) ---
|
|
@@ -76,16 +77,67 @@ async function runComprehensiveDemo() {
|
|
|
76
77
|
});
|
|
77
78
|
console.log(`\n✅ Toggle Result: HTTPS enabled: ${isSecure}`);
|
|
78
79
|
|
|
79
|
-
// --- 7.
|
|
80
|
+
// --- 7. List / Tags Input (New) ---
|
|
81
|
+
const keywords = await MepCLI.list({
|
|
82
|
+
message: "Enter keywords for package.json (Enter to add, Backspace to remove):",
|
|
83
|
+
initial: ["cli", "mep"],
|
|
84
|
+
validate: (tags) => tags.length > 0 || "Please add at least one keyword."
|
|
85
|
+
});
|
|
86
|
+
console.log(`\n✅ List Result: Keywords: [${keywords.join(', ')}]`);
|
|
87
|
+
|
|
88
|
+
// --- 8. Slider / Scale (New) ---
|
|
89
|
+
const brightness = await MepCLI.slider({
|
|
90
|
+
message: "Set initial brightness:",
|
|
91
|
+
min: 0,
|
|
92
|
+
max: 100,
|
|
93
|
+
initial: 80,
|
|
94
|
+
step: 5,
|
|
95
|
+
unit: "%"
|
|
96
|
+
});
|
|
97
|
+
console.log(`\n✅ Slider Result: Brightness: ${brightness}%`);
|
|
98
|
+
|
|
99
|
+
// --- 9. Date / Time Picker (New) ---
|
|
100
|
+
// We capture 'now' once to ensure initial >= min
|
|
101
|
+
const now = new Date();
|
|
102
|
+
const releaseDate = await MepCLI.date({
|
|
103
|
+
message: "Schedule release date:",
|
|
104
|
+
initial: now,
|
|
105
|
+
min: now // Cannot be in the past
|
|
106
|
+
});
|
|
107
|
+
console.log(`\n✅ Date Result: Release set for: ${releaseDate.toLocaleString()}`);
|
|
108
|
+
|
|
109
|
+
// --- 10. File Path Selector (New) ---
|
|
110
|
+
const configPath = await MepCLI.file({
|
|
111
|
+
message: "Select configuration file (Tab to autocomplete):",
|
|
112
|
+
basePath: process.cwd()
|
|
113
|
+
});
|
|
114
|
+
console.log(`\n✅ File Result: Path: ${configPath}`);
|
|
115
|
+
|
|
116
|
+
// --- 11. Multi-Select Autocomplete (New) ---
|
|
117
|
+
const linters = await MepCLI.multiSelect({
|
|
118
|
+
message: "Select linters to install (Type to search, Space to select):",
|
|
119
|
+
choices: [
|
|
120
|
+
{ title: "ESLint", value: "eslint", selected: true },
|
|
121
|
+
{ title: "Prettier", value: "prettier" },
|
|
122
|
+
{ title: "Stylelint", value: "stylelint" },
|
|
123
|
+
{ title: "TSLint (Deprecated)", value: "tslint" },
|
|
124
|
+
{ title: "JSHint", value: "jshint" },
|
|
125
|
+
{ title: "StandardJS", value: "standard" }
|
|
126
|
+
],
|
|
127
|
+
min: 1
|
|
128
|
+
});
|
|
129
|
+
console.log(`\n✅ MultiSelect Result: Linters: [${linters.join(', ')}]`);
|
|
130
|
+
|
|
131
|
+
// --- 12. Confirm Prompt (Simple Yes/No) ---
|
|
80
132
|
const proceed = await MepCLI.confirm({
|
|
81
133
|
message: "Ready to deploy the project now?",
|
|
82
134
|
initial: true
|
|
83
135
|
});
|
|
84
136
|
console.log(`\n✅ Confirm Result: Deployment decision: ${proceed ? 'Proceed' : 'Cancel'}`);
|
|
85
137
|
|
|
86
|
-
// ---
|
|
138
|
+
// --- 13. Spin Utility (Loading/Async Task Indicator) ---
|
|
87
139
|
await MepCLI.spin(
|
|
88
|
-
"Finalizing configuration and deploying
|
|
140
|
+
"Finalizing configuration and deploying...",
|
|
89
141
|
new Promise(resolve => setTimeout(resolve, 1500)) // Simulates a 1.5 second async task
|
|
90
142
|
);
|
|
91
143
|
console.log("\n--- Deployment successful! All MepCLI features demonstrated! ---");
|