mepcli 0.2.0 → 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/dist/core.js CHANGED
@@ -2,611 +2,18 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MepCLI = void 0;
4
4
  const ansi_1 = require("./ansi");
5
- /**
6
- * Abstract base class for all prompts.
7
- * Handles common logic like stdin management, raw mode, and cleanup
8
- * to enforce DRY (Don't Repeat Yourself) principles.
9
- */
10
- class Prompt {
11
- constructor(options) {
12
- this.options = options;
13
- this.stdin = process.stdin;
14
- this.stdout = process.stdout;
15
- }
16
- print(text) {
17
- this.stdout.write(text);
18
- }
19
- /**
20
- * Starts the prompt interaction.
21
- * Sets up raw mode and listeners, returning a Promise.
22
- */
23
- run() {
24
- return new Promise((resolve, reject) => {
25
- this._resolve = resolve;
26
- this._reject = reject;
27
- if (typeof this.stdin.setRawMode === 'function') {
28
- this.stdin.setRawMode(true);
29
- }
30
- this.stdin.resume();
31
- this.stdin.setEncoding('utf8');
32
- // Initial render: Default to hidden cursor (good for menus)
33
- // Subclasses like TextPrompt will explicitly show it if needed.
34
- this.print(ansi_1.ANSI.HIDE_CURSOR);
35
- this.render(true);
36
- this._onDataHandler = (buffer) => {
37
- const char = buffer.toString();
38
- // Global Exit Handler (Ctrl+C)
39
- if (char === '\u0003') {
40
- this.cleanup();
41
- this.print(ansi_1.ANSI.SHOW_CURSOR + '\n');
42
- if (this._reject)
43
- this._reject(new Error('User force closed'));
44
- return;
45
- }
46
- this.handleInput(char, buffer);
47
- };
48
- this.stdin.on('data', this._onDataHandler);
49
- });
50
- }
51
- /**
52
- * Cleans up listeners and restores stdin state.
53
- */
54
- cleanup() {
55
- if (this._onDataHandler) {
56
- this.stdin.removeListener('data', this._onDataHandler);
57
- }
58
- if (typeof this.stdin.setRawMode === 'function') {
59
- this.stdin.setRawMode(false);
60
- }
61
- this.stdin.pause();
62
- this.print(ansi_1.ANSI.SHOW_CURSOR);
63
- }
64
- /**
65
- * Submits the final value and resolves the promise.
66
- */
67
- submit(result) {
68
- this.cleanup();
69
- this.print('\n');
70
- if (this._resolve)
71
- this._resolve(result);
72
- }
73
- }
74
- // --- Implementation: Text Prompt ---
75
- class TextPrompt extends Prompt {
76
- constructor(options) {
77
- super(options);
78
- this.errorMsg = '';
79
- this.cursor = 0;
80
- this.hasTyped = false;
81
- this.value = options.initial || '';
82
- this.cursor = this.value.length;
83
- }
84
- render(firstRender) {
85
- // TextPrompt needs the cursor visible!
86
- this.print(ansi_1.ANSI.SHOW_CURSOR);
87
- if (!firstRender) {
88
- this.print(ansi_1.ANSI.ERASE_LINE + ansi_1.ANSI.CURSOR_LEFT);
89
- if (this.errorMsg) {
90
- this.print(ansi_1.ANSI.UP + ansi_1.ANSI.ERASE_LINE + ansi_1.ANSI.CURSOR_LEFT);
91
- }
92
- }
93
- // 1. Render the Prompt Message
94
- this.print(ansi_1.ANSI.ERASE_LINE + ansi_1.ANSI.CURSOR_LEFT);
95
- const icon = this.errorMsg ? `${MepCLI.theme.error}✖` : `${MepCLI.theme.success}?`;
96
- this.print(`${icon} ${ansi_1.ANSI.BOLD}${MepCLI.theme.title}${this.options.message}${ansi_1.ANSI.RESET} `);
97
- // 2. Render the Value or Placeholder
98
- if (!this.value && this.options.placeholder && !this.errorMsg && !this.hasTyped) {
99
- this.print(`${MepCLI.theme.muted}${this.options.placeholder}${ansi_1.ANSI.RESET}`);
100
- // Move cursor back to start so typing overwrites placeholder visually
101
- this.print(`\x1b[${this.options.placeholder.length}D`);
102
- }
103
- else {
104
- const displayValue = this.options.isPassword ? '*'.repeat(this.value.length) : this.value;
105
- this.print(`${MepCLI.theme.main}${displayValue}${ansi_1.ANSI.RESET}`);
106
- }
107
- // 3. Handle Error Message
108
- if (this.errorMsg) {
109
- this.print(`\n${ansi_1.ANSI.ERASE_LINE}${MepCLI.theme.error}>> ${this.errorMsg}${ansi_1.ANSI.RESET}`);
110
- this.print(ansi_1.ANSI.UP); // Go back to input line
111
- // Re-calculate position to end of input
112
- const promptLen = this.options.message.length + 3; // Icon + 2 spaces
113
- const valLen = this.value.length;
114
- // Move to absolute start of line, then move right to end of string
115
- this.print(`\x1b[1000D\x1b[${promptLen + valLen}C`);
116
- }
117
- // 4. Position Cursor Logic
118
- // At this point, the physical cursor is at the END of the value string.
119
- // We need to move it LEFT by (length - cursor_index)
120
- const diff = this.value.length - this.cursor;
121
- if (diff > 0) {
122
- this.print(`\x1b[${diff}D`);
123
- }
124
- }
125
- handleInput(char) {
126
- // Enter
127
- if (char === '\r' || char === '\n') {
128
- if (this.options.validate) {
129
- const validationResult = this.options.validate(this.value);
130
- if (typeof validationResult === 'string' && validationResult.length > 0) {
131
- this.errorMsg = validationResult;
132
- this.render(false);
133
- return;
134
- }
135
- }
136
- if (this.errorMsg) {
137
- this.print(`\n${ansi_1.ANSI.ERASE_LINE}${ansi_1.ANSI.UP}`);
138
- }
139
- this.submit(this.value);
140
- return;
141
- }
142
- // Backspace
143
- if (char === '\u0008' || char === '\x7f') {
144
- this.hasTyped = true;
145
- if (this.cursor > 0) {
146
- this.value = this.value.slice(0, this.cursor - 1) + this.value.slice(this.cursor);
147
- this.cursor--;
148
- this.errorMsg = '';
149
- this.render(false);
150
- }
151
- return;
152
- }
153
- // Arrow Left
154
- if (char === '\u001b[D') {
155
- if (this.cursor > 0) {
156
- this.cursor--;
157
- this.render(false);
158
- }
159
- return;
160
- }
161
- // Arrow Right
162
- if (char === '\u001b[C') {
163
- if (this.cursor < this.value.length) {
164
- this.cursor++;
165
- this.render(false);
166
- }
167
- return;
168
- }
169
- // Delete key
170
- if (char === '\u001b[3~') {
171
- this.hasTyped = true;
172
- if (this.cursor < this.value.length) {
173
- this.value = this.value.slice(0, this.cursor) + this.value.slice(this.cursor + 1);
174
- this.errorMsg = '';
175
- this.render(false);
176
- }
177
- return;
178
- }
179
- // Regular Typing
180
- if (char.length === 1 && !/^[\x00-\x1F]/.test(char)) {
181
- this.hasTyped = true;
182
- this.value = this.value.slice(0, this.cursor) + char + this.value.slice(this.cursor);
183
- this.cursor++;
184
- this.errorMsg = '';
185
- this.render(false);
186
- }
187
- }
188
- }
189
- // --- Implementation: Select Prompt ---
190
- class SelectPrompt extends Prompt {
191
- constructor(options) {
192
- super(options);
193
- this.selectedIndex = 0;
194
- this.searchBuffer = '';
195
- // Custom render to handle variable height clearing
196
- this.lastRenderHeight = 0;
197
- // Find first non-separator index
198
- this.selectedIndex = this.findNextSelectableIndex(-1, 1);
199
- }
200
- isSeparator(item) {
201
- return item && item.separator === true;
202
- }
203
- findNextSelectableIndex(currentIndex, direction) {
204
- let nextIndex = currentIndex + direction;
205
- const choices = this.getFilteredChoices();
206
- // Loop around logic
207
- if (nextIndex < 0)
208
- nextIndex = choices.length - 1;
209
- if (nextIndex >= choices.length)
210
- nextIndex = 0;
211
- if (choices.length === 0)
212
- return 0;
213
- // Safety check to prevent infinite loop if all are separators (shouldn't happen in practice)
214
- let count = 0;
215
- while (this.isSeparator(choices[nextIndex]) && count < choices.length) {
216
- nextIndex += direction;
217
- if (nextIndex < 0)
218
- nextIndex = choices.length - 1;
219
- if (nextIndex >= choices.length)
220
- nextIndex = 0;
221
- count++;
222
- }
223
- return nextIndex;
224
- }
225
- getFilteredChoices() {
226
- if (!this.searchBuffer)
227
- return this.options.choices;
228
- return this.options.choices.filter(c => {
229
- if (this.isSeparator(c))
230
- return false; // Hide separators when searching
231
- return c.title.toLowerCase().includes(this.searchBuffer.toLowerCase());
232
- });
233
- }
234
- renderWrapper(firstRender) {
235
- if (!firstRender && this.lastRenderHeight > 0) {
236
- this.print(`\x1b[${this.lastRenderHeight}A`);
237
- }
238
- let output = '';
239
- const choices = this.getFilteredChoices();
240
- // Header
241
- const searchStr = this.searchBuffer ? ` ${MepCLI.theme.muted}(Filter: ${this.searchBuffer})${ansi_1.ANSI.RESET}` : '';
242
- output += `${ansi_1.ANSI.ERASE_LINE}${ansi_1.ANSI.CURSOR_LEFT}${MepCLI.theme.success}?${ansi_1.ANSI.RESET} ${ansi_1.ANSI.BOLD}${MepCLI.theme.title}${this.options.message}${ansi_1.ANSI.RESET}${searchStr}\n`;
243
- if (choices.length === 0) {
244
- output += `${ansi_1.ANSI.ERASE_LINE}${ansi_1.ANSI.CURSOR_LEFT} ${MepCLI.theme.muted}No results found${ansi_1.ANSI.RESET}\n`;
245
- }
246
- else {
247
- choices.forEach((choice, index) => {
248
- output += `${ansi_1.ANSI.ERASE_LINE}${ansi_1.ANSI.CURSOR_LEFT}`;
249
- if (this.isSeparator(choice)) {
250
- output += ` ${ansi_1.ANSI.DIM}${choice.text || '────────'}${ansi_1.ANSI.RESET}\n`;
251
- }
252
- else {
253
- if (index === this.selectedIndex) {
254
- output += `${MepCLI.theme.main}❯ ${choice.title}${ansi_1.ANSI.RESET}\n`;
255
- }
256
- else {
257
- output += ` ${choice.title}\n`;
258
- }
259
- }
260
- });
261
- }
262
- this.print(output);
263
- // Clear remaining lines if list shrunk
264
- const currentHeight = choices.length + 1 + (choices.length === 0 ? 1 : 0);
265
- const linesToClear = this.lastRenderHeight - currentHeight;
266
- if (linesToClear > 0) {
267
- for (let i = 0; i < linesToClear; i++) {
268
- this.print(`${ansi_1.ANSI.ERASE_LINE}\n`);
269
- }
270
- this.print(`\x1b[${linesToClear}A`); // Move back up
271
- }
272
- this.lastRenderHeight = currentHeight;
273
- }
274
- render(firstRender) {
275
- this.print(ansi_1.ANSI.HIDE_CURSOR);
276
- this.renderWrapper(firstRender);
277
- }
278
- handleInput(char) {
279
- const choices = this.getFilteredChoices();
280
- if (char === '\r' || char === '\n') {
281
- if (choices.length === 0) {
282
- this.searchBuffer = '';
283
- this.selectedIndex = this.findNextSelectableIndex(-1, 1);
284
- this.render(false);
285
- return;
286
- }
287
- if (this.isSeparator(choices[this.selectedIndex]))
288
- return;
289
- this.cleanup();
290
- this.print(ansi_1.ANSI.SHOW_CURSOR);
291
- if (this._resolve)
292
- this._resolve(choices[this.selectedIndex].value);
293
- return;
294
- }
295
- if (char === '\u001b[A') { // Up
296
- if (choices.length > 0) {
297
- this.selectedIndex = this.findNextSelectableIndex(this.selectedIndex, -1);
298
- this.render(false);
299
- }
300
- return;
301
- }
302
- if (char === '\u001b[B') { // Down
303
- if (choices.length > 0) {
304
- this.selectedIndex = this.findNextSelectableIndex(this.selectedIndex, 1);
305
- this.render(false);
306
- }
307
- return;
308
- }
309
- // Backspace
310
- if (char === '\u0008' || char === '\x7f') {
311
- if (this.searchBuffer.length > 0) {
312
- this.searchBuffer = this.searchBuffer.slice(0, -1);
313
- this.selectedIndex = 0; // Reset selection
314
- this.selectedIndex = this.findNextSelectableIndex(-1, 1);
315
- this.render(false);
316
- }
317
- return;
318
- }
319
- // Typing
320
- if (char.length === 1 && !/^[\x00-\x1F]/.test(char)) {
321
- this.searchBuffer += char;
322
- this.selectedIndex = 0; // Reset selection
323
- this.selectedIndex = this.findNextSelectableIndex(-1, 1);
324
- this.render(false);
325
- }
326
- }
327
- }
328
- // --- Implementation: Checkbox Prompt ---
329
- class CheckboxPrompt extends Prompt {
330
- constructor(options) {
331
- super(options);
332
- this.selectedIndex = 0;
333
- this.errorMsg = '';
334
- this.checkedState = options.choices.map(c => !!c.selected);
335
- }
336
- render(firstRender) {
337
- // Ensure cursor is HIDDEN for menus
338
- this.print(ansi_1.ANSI.HIDE_CURSOR);
339
- if (!firstRender) {
340
- const extraLines = this.errorMsg ? 1 : 0;
341
- this.print(`\x1b[${this.options.choices.length + 1 + extraLines}A`);
342
- }
343
- this.print(`${ansi_1.ANSI.ERASE_LINE}${ansi_1.ANSI.CURSOR_LEFT}`);
344
- const icon = this.errorMsg ? `${MepCLI.theme.error}✖` : `${MepCLI.theme.success}?`;
345
- this.print(`${icon} ${ansi_1.ANSI.BOLD}${MepCLI.theme.title}${this.options.message}${ansi_1.ANSI.RESET} ${MepCLI.theme.muted}(Press <space> to select, <enter> to confirm)${ansi_1.ANSI.RESET}\n`);
346
- this.options.choices.forEach((choice, index) => {
347
- this.print(`${ansi_1.ANSI.ERASE_LINE}${ansi_1.ANSI.CURSOR_LEFT}`);
348
- const cursor = index === this.selectedIndex ? `${MepCLI.theme.main}❯${ansi_1.ANSI.RESET}` : ' ';
349
- const isChecked = this.checkedState[index];
350
- const checkbox = isChecked
351
- ? `${MepCLI.theme.success}◉${ansi_1.ANSI.RESET}`
352
- : `${MepCLI.theme.muted}◯${ansi_1.ANSI.RESET}`;
353
- const title = index === this.selectedIndex
354
- ? `${MepCLI.theme.main}${choice.title}${ansi_1.ANSI.RESET}`
355
- : choice.title;
356
- this.print(`${cursor} ${checkbox} ${title}\n`);
357
- });
358
- if (this.errorMsg) {
359
- this.print(`${ansi_1.ANSI.ERASE_LINE}${MepCLI.theme.error}>> ${this.errorMsg}${ansi_1.ANSI.RESET}`);
360
- }
361
- else if (!firstRender) {
362
- this.print(`${ansi_1.ANSI.ERASE_LINE}`);
363
- }
364
- }
365
- handleInput(char) {
366
- if (char === '\r' || char === '\n') {
367
- const selectedCount = this.checkedState.filter(Boolean).length;
368
- const { min = 0, max } = this.options;
369
- if (selectedCount < min) {
370
- this.errorMsg = `You must select at least ${min} options.`;
371
- this.render(false);
372
- return;
373
- }
374
- if (max && selectedCount > max) {
375
- this.errorMsg = `You can only select up to ${max} options.`;
376
- this.render(false);
377
- return;
378
- }
379
- this.cleanup();
380
- this.print(ansi_1.ANSI.SHOW_CURSOR + '\n');
381
- const results = this.options.choices
382
- .filter((_, i) => this.checkedState[i])
383
- .map(c => c.value);
384
- if (this._resolve)
385
- this._resolve(results);
386
- return;
387
- }
388
- if (char === ' ') {
389
- const currentChecked = this.checkedState[this.selectedIndex];
390
- const selectedCount = this.checkedState.filter(Boolean).length;
391
- const { max } = this.options;
392
- if (!currentChecked && max && selectedCount >= max) {
393
- this.errorMsg = `Max ${max} selections allowed.`;
394
- }
395
- else {
396
- this.checkedState[this.selectedIndex] = !currentChecked;
397
- this.errorMsg = '';
398
- }
399
- this.render(false);
400
- }
401
- if (char === '\u001b[A') { // Up
402
- this.selectedIndex = this.selectedIndex > 0 ? this.selectedIndex - 1 : this.options.choices.length - 1;
403
- this.errorMsg = '';
404
- this.render(false);
405
- }
406
- if (char === '\u001b[B') { // Down
407
- this.selectedIndex = this.selectedIndex < this.options.choices.length - 1 ? this.selectedIndex + 1 : 0;
408
- this.errorMsg = '';
409
- this.render(false);
410
- }
411
- }
412
- }
413
- // --- Implementation: Confirm Prompt ---
414
- class ConfirmPrompt extends Prompt {
415
- constructor(options) {
416
- super(options);
417
- this.value = options.initial ?? true;
418
- }
419
- render(firstRender) {
420
- // Hide cursor for confirm, user just hits Y/N or Enter
421
- this.print(ansi_1.ANSI.HIDE_CURSOR);
422
- if (!firstRender) {
423
- this.print(`${ansi_1.ANSI.ERASE_LINE}${ansi_1.ANSI.CURSOR_LEFT}`);
424
- }
425
- const hint = this.value ? `${ansi_1.ANSI.BOLD}Yes${ansi_1.ANSI.RESET}/no` : `yes/${ansi_1.ANSI.BOLD}No${ansi_1.ANSI.RESET}`;
426
- this.print(`${MepCLI.theme.success}?${ansi_1.ANSI.RESET} ${ansi_1.ANSI.BOLD}${MepCLI.theme.title}${this.options.message}${ansi_1.ANSI.RESET} ${MepCLI.theme.muted}(${hint})${ansi_1.ANSI.RESET} `);
427
- const text = this.value ? 'Yes' : 'No';
428
- this.print(`${MepCLI.theme.main}${text}${ansi_1.ANSI.RESET}\x1b[${text.length}D`);
429
- }
430
- handleInput(char) {
431
- const c = char.toLowerCase();
432
- if (c === '\r' || c === '\n') {
433
- this.submit(this.value);
434
- return;
435
- }
436
- if (c === 'y') {
437
- this.value = true;
438
- this.render(false);
439
- }
440
- if (c === 'n') {
441
- this.value = false;
442
- this.render(false);
443
- }
444
- }
445
- }
446
- // --- Implementation: Toggle Prompt ---
447
- class TogglePrompt extends Prompt {
448
- constructor(options) {
449
- super(options);
450
- this.value = options.initial ?? false;
451
- }
452
- render(firstRender) {
453
- this.print(ansi_1.ANSI.HIDE_CURSOR);
454
- if (!firstRender) {
455
- this.print(`${ansi_1.ANSI.ERASE_LINE}${ansi_1.ANSI.CURSOR_LEFT}`);
456
- }
457
- const activeText = this.options.activeText || 'ON';
458
- const inactiveText = this.options.inactiveText || 'OFF';
459
- let toggleDisplay = '';
460
- if (this.value) {
461
- toggleDisplay = `${MepCLI.theme.main}[${ansi_1.ANSI.BOLD}${activeText}${ansi_1.ANSI.RESET}${MepCLI.theme.main}]${ansi_1.ANSI.RESET} ${MepCLI.theme.muted}${inactiveText}${ansi_1.ANSI.RESET}`;
462
- }
463
- else {
464
- toggleDisplay = `${MepCLI.theme.muted}${activeText}${ansi_1.ANSI.RESET} ${MepCLI.theme.main}[${ansi_1.ANSI.BOLD}${inactiveText}${ansi_1.ANSI.RESET}${MepCLI.theme.main}]${ansi_1.ANSI.RESET}`;
465
- }
466
- this.print(`${MepCLI.theme.success}?${ansi_1.ANSI.RESET} ${ansi_1.ANSI.BOLD}${MepCLI.theme.title}${this.options.message}${ansi_1.ANSI.RESET} ${toggleDisplay}`);
467
- this.print(`\x1b[${toggleDisplay.length}D`); // Move back is not really needed as we hide cursor, but kept for consistency
468
- }
469
- handleInput(char) {
470
- if (char === '\r' || char === '\n') {
471
- this.submit(this.value);
472
- return;
473
- }
474
- if (char === '\u001b[D' || char === '\u001b[C' || char === 'h' || char === 'l') { // Left/Right
475
- this.value = !this.value;
476
- this.render(false);
477
- }
478
- if (char === ' ') {
479
- this.value = !this.value;
480
- this.render(false);
481
- }
482
- }
483
- }
484
- // --- Implementation: Number Prompt ---
485
- class NumberPrompt extends Prompt {
486
- constructor(options) {
487
- super(options);
488
- this.cursor = 0;
489
- this.errorMsg = '';
490
- this.value = options.initial ?? 0;
491
- this.stringValue = this.value.toString();
492
- this.cursor = this.stringValue.length;
493
- }
494
- render(firstRender) {
495
- this.print(ansi_1.ANSI.SHOW_CURSOR);
496
- if (!firstRender) {
497
- this.print(ansi_1.ANSI.ERASE_LINE + ansi_1.ANSI.CURSOR_LEFT);
498
- if (this.errorMsg) {
499
- this.print(ansi_1.ANSI.UP + ansi_1.ANSI.ERASE_LINE + ansi_1.ANSI.CURSOR_LEFT);
500
- }
501
- }
502
- // 1. Render the Prompt Message
503
- this.print(ansi_1.ANSI.ERASE_LINE + ansi_1.ANSI.CURSOR_LEFT);
504
- const icon = this.errorMsg ? `${MepCLI.theme.error}✖` : `${MepCLI.theme.success}?`;
505
- this.print(`${icon} ${ansi_1.ANSI.BOLD}${MepCLI.theme.title}${this.options.message}${ansi_1.ANSI.RESET} `);
506
- // 2. Render the Value
507
- this.print(`${MepCLI.theme.main}${this.stringValue}${ansi_1.ANSI.RESET}`);
508
- // 3. Handle Error Message
509
- if (this.errorMsg) {
510
- this.print(`\n${ansi_1.ANSI.ERASE_LINE}${MepCLI.theme.error}>> ${this.errorMsg}${ansi_1.ANSI.RESET}`);
511
- this.print(ansi_1.ANSI.UP);
512
- const promptLen = this.options.message.length + 3;
513
- const valLen = this.stringValue.length;
514
- this.print(`\x1b[1000D\x1b[${promptLen + valLen}C`);
515
- }
516
- // 4. Position Cursor
517
- const diff = this.stringValue.length - this.cursor;
518
- if (diff > 0) {
519
- this.print(`\x1b[${diff}D`);
520
- }
521
- }
522
- handleInput(char) {
523
- // Enter
524
- if (char === '\r' || char === '\n') {
525
- const num = parseFloat(this.stringValue);
526
- if (isNaN(num)) {
527
- this.errorMsg = 'Please enter a valid number.';
528
- this.render(false);
529
- return;
530
- }
531
- if (this.options.min !== undefined && num < this.options.min) {
532
- this.errorMsg = `Minimum value is ${this.options.min}`;
533
- this.render(false);
534
- return;
535
- }
536
- if (this.options.max !== undefined && num > this.options.max) {
537
- this.errorMsg = `Maximum value is ${this.options.max}`;
538
- this.render(false);
539
- return;
540
- }
541
- if (this.errorMsg) {
542
- this.print(`\n${ansi_1.ANSI.ERASE_LINE}${ansi_1.ANSI.UP}`);
543
- }
544
- this.submit(num);
545
- return;
546
- }
547
- // Up Arrow (Increment)
548
- if (char === '\u001b[A') {
549
- let num = parseFloat(this.stringValue) || 0;
550
- num += (this.options.step ?? 1);
551
- if (this.options.max !== undefined && num > this.options.max)
552
- num = this.options.max;
553
- this.stringValue = num.toString();
554
- this.cursor = this.stringValue.length;
555
- this.errorMsg = '';
556
- this.render(false);
557
- return;
558
- }
559
- // Down Arrow (Decrement)
560
- if (char === '\u001b[B') {
561
- let num = parseFloat(this.stringValue) || 0;
562
- num -= (this.options.step ?? 1);
563
- if (this.options.min !== undefined && num < this.options.min)
564
- num = this.options.min;
565
- this.stringValue = num.toString();
566
- this.cursor = this.stringValue.length;
567
- this.errorMsg = '';
568
- this.render(false);
569
- return;
570
- }
571
- // Backspace
572
- if (char === '\u0008' || char === '\x7f') {
573
- if (this.cursor > 0) {
574
- this.stringValue = this.stringValue.slice(0, this.cursor - 1) + this.stringValue.slice(this.cursor);
575
- this.cursor--;
576
- this.errorMsg = '';
577
- this.render(false);
578
- }
579
- return;
580
- }
581
- // Arrow Left
582
- if (char === '\u001b[D') {
583
- if (this.cursor > 0) {
584
- this.cursor--;
585
- this.render(false);
586
- }
587
- return;
588
- }
589
- // Arrow Right
590
- if (char === '\u001b[C') {
591
- if (this.cursor < this.stringValue.length) {
592
- this.cursor++;
593
- this.render(false);
594
- }
595
- return;
596
- }
597
- // Numeric Input (and . and -)
598
- if (/^[0-9.\-]$/.test(char)) {
599
- if (char === '-' && (this.cursor !== 0 || this.stringValue.includes('-')))
600
- return;
601
- if (char === '.' && this.stringValue.includes('.'))
602
- return;
603
- this.stringValue = this.stringValue.slice(0, this.cursor) + char + this.stringValue.slice(this.cursor);
604
- this.cursor++;
605
- this.errorMsg = '';
606
- this.render(false);
607
- }
608
- }
609
- }
5
+ const theme_1 = require("./theme");
6
+ const text_1 = require("./prompts/text");
7
+ const select_1 = require("./prompts/select");
8
+ const checkbox_1 = require("./prompts/checkbox");
9
+ const confirm_1 = require("./prompts/confirm");
10
+ const toggle_1 = require("./prompts/toggle");
11
+ const number_1 = require("./prompts/number");
12
+ const list_1 = require("./prompts/list");
13
+ const slider_1 = require("./prompts/slider");
14
+ const date_1 = require("./prompts/date");
15
+ const file_1 = require("./prompts/file");
16
+ const multi_select_1 = require("./prompts/multi-select");
610
17
  /**
611
18
  * Public Facade for MepCLI
612
19
  */
@@ -637,32 +44,41 @@ class MepCLI {
637
44
  }
638
45
  }
639
46
  static text(options) {
640
- return new TextPrompt(options).run();
47
+ return new text_1.TextPrompt(options).run();
641
48
  }
642
49
  static select(options) {
643
- return new SelectPrompt(options).run();
50
+ return new select_1.SelectPrompt(options).run();
644
51
  }
645
52
  static checkbox(options) {
646
- return new CheckboxPrompt(options).run();
53
+ return new checkbox_1.CheckboxPrompt(options).run();
647
54
  }
648
55
  static confirm(options) {
649
- return new ConfirmPrompt(options).run();
56
+ return new confirm_1.ConfirmPrompt(options).run();
650
57
  }
651
58
  static password(options) {
652
- return new TextPrompt({ ...options, isPassword: true }).run();
59
+ return new text_1.TextPrompt({ ...options, isPassword: true }).run();
653
60
  }
654
61
  static number(options) {
655
- return new NumberPrompt(options).run();
62
+ return new number_1.NumberPrompt(options).run();
656
63
  }
657
64
  static toggle(options) {
658
- return new TogglePrompt(options).run();
65
+ return new toggle_1.TogglePrompt(options).run();
66
+ }
67
+ static list(options) {
68
+ return new list_1.ListPrompt(options).run();
69
+ }
70
+ static slider(options) {
71
+ return new slider_1.SliderPrompt(options).run();
72
+ }
73
+ static date(options) {
74
+ return new date_1.DatePrompt(options).run();
75
+ }
76
+ static file(options) {
77
+ return new file_1.FilePrompt(options).run();
78
+ }
79
+ static multiSelect(options) {
80
+ return new multi_select_1.MultiSelectPrompt(options).run();
659
81
  }
660
82
  }
661
83
  exports.MepCLI = MepCLI;
662
- MepCLI.theme = {
663
- main: ansi_1.ANSI.FG_CYAN,
664
- success: ansi_1.ANSI.FG_GREEN,
665
- error: ansi_1.ANSI.FG_RED,
666
- muted: ansi_1.ANSI.FG_GRAY,
667
- title: ansi_1.ANSI.RESET
668
- };
84
+ MepCLI.theme = theme_1.theme;
@@ -0,0 +1,10 @@
1
+ import { Prompt } from '../base';
2
+ import { CheckboxOptions } from '../types';
3
+ export declare class CheckboxPrompt extends Prompt<any[], CheckboxOptions> {
4
+ private selectedIndex;
5
+ private checkedState;
6
+ private errorMsg;
7
+ constructor(options: CheckboxOptions);
8
+ protected render(firstRender: boolean): void;
9
+ protected handleInput(char: string): void;
10
+ }