-
-
Notifications
You must be signed in to change notification settings - Fork 63
/
select.ts
131 lines (115 loc) 路 3.56 KB
/
select.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import { blue, underline, yellow } from "./deps.ts";
import { Figures } from "./figures.ts";
import {
GenericList,
GenericListKeys,
GenericListOption,
GenericListOptions,
GenericListOptionSettings,
GenericListSettings,
} from "./_generic_list.ts";
import { GenericPrompt } from "./_generic_prompt.ts";
/** Select key options. */
export type SelectKeys = GenericListKeys;
/** Select option options. */
export type SelectOption = GenericListOption;
/** Select option settings. */
export type SelectOptionSettings = GenericListOptionSettings;
/** Select options type. */
export type SelectValueOptions = (string | SelectOption)[];
/** Select option settings type. */
export type SelectValueSettings = SelectOptionSettings[];
/** Select prompt options. */
export interface SelectOptions extends GenericListOptions<string, string> {
options: SelectValueOptions;
keys?: SelectKeys;
}
/** Select prompt settings. */
export interface SelectSettings extends GenericListSettings<string, string> {
options: SelectValueSettings;
keys?: SelectKeys;
}
/** Select prompt representation. */
export class Select<S extends SelectSettings = SelectSettings>
extends GenericList<string, string, S> {
protected listIndex: number = this.getListIndex(this.settings.default);
/**
* Inject prompt value. Can be used for unit tests or pre selections.
* @param value Input value.
*/
public static inject(value: string): void {
GenericPrompt.inject(value);
}
/** Execute the prompt and show cursor on end. */
public static prompt(options: SelectOptions): Promise<string> {
return new this({
pointer: blue(Figures.POINTER_SMALL),
prefix: yellow("? "),
indent: " ",
listPointer: blue(Figures.POINTER),
maxRows: 10,
searchLabel: blue(Figures.SEARCH),
...options,
options: Select.mapOptions(options),
}).prompt();
}
protected static mapOptions(options: SelectOptions): SelectValueSettings {
return options.options
.map((item: string | SelectOption) =>
typeof item === "string" ? { value: item } : item
)
.map((item) => this.mapOption(item));
}
protected input(): string {
return underline(blue(this.inputValue));
}
/**
* Render select option.
* @param item Select option settings.
* @param isSelected Set to true if option is selected.
*/
protected getListItem(
item: SelectOptionSettings,
isSelected?: boolean,
): string {
let line = this.settings.indent;
line += isSelected ? `${this.settings.listPointer} ` : " ";
line += `${
isSelected && !item.disabled
? this.highlight(item.name, (val) => val)
: this.highlight(item.name)
}`;
return line;
}
/** Get value of selected option. */
protected getValue(): string {
return this.options[this.listIndex]?.value ?? this.settings.default;
}
/**
* Validate input value.
* @param value User input value.
* @return True on success, false or error message on error.
*/
protected validate(value: string): boolean | string {
return typeof value === "string" &&
value.length > 0 &&
this.options.findIndex((option: SelectOptionSettings) =>
option.value === value
) !== -1;
}
/**
* Map input value to output value.
* @param value Input value.
* @return Output value.
*/
protected transform(value: string): string {
return value.trim();
}
/**
* Format output value.
* @param value Output value.
*/
protected format(value: string): string {
return this.getOptionByValue(value)?.name ?? value;
}
}