-
Notifications
You must be signed in to change notification settings - Fork 205
/
Copy pathprompt.ts
98 lines (81 loc) · 2.43 KB
/
prompt.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
import prompts from 'prompts';
type Choice = {
title: string;
value: string;
description?: string;
};
export type Question<T extends string> = Omit<
prompts.PromptObject<T>,
'validate' | 'name' | 'choices'
> & {
name: T;
validate?: (value: string) => boolean | string;
choices?:
| Choice[]
| ((prev: unknown, values: Partial<prompts.Answers<T>>) => Choice[]);
};
/**
* Wrapper around `prompts` with additional features:
*
* - Improved type-safety
* - Read answers from passed arguments
* - Skip questions with a single choice
* - Exit on canceling the prompt
*/
export async function prompt<T extends string>(
questions: Question<T>[] | Question<T>,
argv?: Record<T, string>,
options?: prompts.Options
) {
const singleChoiceAnswers = {};
const promptQuestions = [];
if (Array.isArray(questions)) {
for (const question of questions) {
// Skip questions which are passed as parameter and pass validation
const argValue = argv?.[question.name];
if (argValue && question.validate?.(argValue) !== false) {
continue;
}
// Don't prompt questions with a single choice
if (Array.isArray(question.choices) && question.choices.length === 1) {
const onlyChoice = question.choices[0];
if (onlyChoice?.value) {
// @ts-expect-error assume the passed value is correct
singleChoiceAnswers[question.name] = onlyChoice.value;
}
continue;
}
const { type, choices } = question;
// Don't prompt dynamic questions with a single choice
if (type === 'select' && typeof choices === 'function') {
question.type = (prev, values) => {
const dynamicChoices = choices(prev, { ...argv, ...values });
if (dynamicChoices && dynamicChoices.length === 1) {
const onlyChoice = dynamicChoices[0];
if (onlyChoice?.value) {
// @ts-expect-error assume the passed value is correct
singleChoiceAnswers[question.name] = onlyChoice.value;
}
return null;
}
return type;
};
}
promptQuestions.push(question);
}
} else {
promptQuestions.push(questions);
}
const promptAnswers = await prompts(promptQuestions, {
onCancel() {
// Exit the CLI on cancel
process.exit(1);
},
...options,
});
return {
...argv,
...singleChoiceAnswers,
...promptAnswers,
};
}