@topcli/prompts 1.2.0 → 1.3.0
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 +44 -18
- package/index.d.ts +35 -5
- package/index.js +2 -1
- package/package.json +1 -1
- package/src/abstract-prompt.js +4 -0
- package/src/confirm-prompt.js +9 -0
- package/src/prompt-agent.js +56 -0
- package/src/question-prompt.js +8 -0
- package/src/select-prompt.js +8 -0
package/README.md
CHANGED
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
[](https://github.com/TopCli/prompts/blob/main/LICENSE)
|
|
6
6
|

|
|
7
7
|
|
|
8
|
-
Node.js user
|
|
8
|
+
Node.js user prompt library for command-line interfaces.
|
|
9
9
|
|
|
10
10
|
## Requirements
|
|
11
|
-
- [Node.js](https://nodejs.org/en/)
|
|
11
|
+
- [Node.js](https://nodejs.org/en/) v16 or higher
|
|
12
12
|
|
|
13
13
|
## Getting Started
|
|
14
14
|
|
|
@@ -89,38 +89,64 @@ Use `ignoreValues` to skip result render & clear lines after a selected one.
|
|
|
89
89
|
confirm(message: string, options?: ConfirmOptions): Promise<boolean>
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
-
Boolean prompt, return `options.initial` if user input is different from
|
|
92
|
+
Boolean prompt, return `options.initial` if user input is different from `y`/`yes`/`n`/`no` (case insensitive), (default `false`).
|
|
93
|
+
|
|
94
|
+
### `PromptAgent`
|
|
95
|
+
|
|
96
|
+
The `PromptAgent` class allows to programmatically set the next answers for any prompt function, this can be useful for testing.
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
const agent = PromptAgent.agent();
|
|
100
|
+
agent.nextAnswer("John");
|
|
101
|
+
|
|
102
|
+
const input = await question("What's your name?");
|
|
103
|
+
assert.equal(input, "John");
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
> [!WARNING]
|
|
107
|
+
> Answers set with `PromptAgent` will **bypass** any logical & validation rules.
|
|
108
|
+
> Examples:
|
|
109
|
+
> - When using `question()`, `validators` functions will not be executed.
|
|
110
|
+
> - When using `select()`, the answer can be different from the available choices.
|
|
111
|
+
> - When using `confirm()`, the answer can be any type other than boolean.
|
|
112
|
+
> **Use with caution**
|
|
93
113
|
|
|
94
114
|
## Interfaces
|
|
95
115
|
|
|
96
116
|
```ts
|
|
97
|
-
export interface
|
|
117
|
+
export interface SharedOptions {
|
|
118
|
+
stdin?: NodeJS.ReadStream & {
|
|
119
|
+
fd: 0;
|
|
120
|
+
};
|
|
121
|
+
stdout?: NodeJS.WriteStream & {
|
|
122
|
+
fd: 1;
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export interface Validator {
|
|
127
|
+
validate: (input: string) => boolean;
|
|
128
|
+
error: (input?: string) => string;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export interface QuestionOptions extends SharedOptions {
|
|
98
132
|
defaultValue?: string;
|
|
99
|
-
validators?:
|
|
100
|
-
validate: (input: string) => boolean;
|
|
101
|
-
error: (input: string) => string;
|
|
102
|
-
}[];
|
|
133
|
+
validators?: Validator[];
|
|
103
134
|
}
|
|
104
|
-
|
|
105
|
-
```ts
|
|
135
|
+
|
|
106
136
|
export interface Choice {
|
|
107
137
|
value: any;
|
|
108
138
|
label: string;
|
|
109
139
|
description?: string;
|
|
110
140
|
}
|
|
111
|
-
```
|
|
112
141
|
|
|
113
|
-
|
|
114
|
-
export interface SelectOptions {
|
|
142
|
+
export interface SelectOptions extends SharedOptions {
|
|
115
143
|
choices: (Choice | string)[];
|
|
116
|
-
maxVisible?: number
|
|
144
|
+
maxVisible?: number;
|
|
117
145
|
ignoreValues?: (string | number | boolean)[];
|
|
118
146
|
}
|
|
119
|
-
```
|
|
120
147
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
initial?: boolean = false;
|
|
148
|
+
export interface ConfirmOptions extends SharedOptions {
|
|
149
|
+
initial?: boolean;
|
|
124
150
|
}
|
|
125
151
|
```
|
|
126
152
|
|
package/index.d.ts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
export interface
|
|
1
|
+
export interface SharedOptions {
|
|
2
2
|
stdin?: NodeJS.ReadStream & {
|
|
3
3
|
fd: 0;
|
|
4
4
|
};
|
|
5
5
|
stdout?: NodeJS.WriteStream & {
|
|
6
6
|
fd: 1;
|
|
7
7
|
};
|
|
8
|
-
defaultValue?: string;
|
|
9
|
-
validators?: Validator[];
|
|
10
8
|
}
|
|
11
9
|
|
|
12
10
|
export interface Validator {
|
|
@@ -14,19 +12,25 @@ export interface Validator {
|
|
|
14
12
|
error: (input?: string) => string;
|
|
15
13
|
}
|
|
16
14
|
|
|
15
|
+
export interface QuestionOptions extends SharedOptions {
|
|
16
|
+
defaultValue?: string;
|
|
17
|
+
validators?: Validator[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
17
21
|
export interface Choice {
|
|
18
22
|
value: any;
|
|
19
23
|
label: string;
|
|
20
24
|
description?: string;
|
|
21
25
|
}
|
|
22
26
|
|
|
23
|
-
export interface SelectOptions {
|
|
27
|
+
export interface SelectOptions extends SharedOptions {
|
|
24
28
|
choices: (Choice | string)[];
|
|
25
29
|
maxVisible?: number;
|
|
26
30
|
ignoreValues?: (string | number | boolean)[];
|
|
27
31
|
}
|
|
28
32
|
|
|
29
|
-
export interface ConfirmOptions {
|
|
33
|
+
export interface ConfirmOptions extends SharedOptions {
|
|
30
34
|
initial?: boolean;
|
|
31
35
|
}
|
|
32
36
|
|
|
@@ -35,3 +39,29 @@ export function select(message: string, options: SelectOptions): Promise<string>
|
|
|
35
39
|
export function confirm(message: string, options?: ConfirmOptions): Promise<boolean>;
|
|
36
40
|
|
|
37
41
|
export function required(): Validator;
|
|
42
|
+
|
|
43
|
+
export class PromptAgent {
|
|
44
|
+
/**
|
|
45
|
+
* The prompts answers queue.
|
|
46
|
+
* When not empty, any prompt will be answered by the first answer in this list.
|
|
47
|
+
*/
|
|
48
|
+
nextAnswers: Array<string | boolean>;
|
|
49
|
+
|
|
50
|
+
static get agent(): PromptAgent;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Programmatically set the next answer for any prompt (`question()`, `confirm()`, `select()`)
|
|
54
|
+
*
|
|
55
|
+
* This is useful for testing.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```js
|
|
59
|
+
* const promptAgent = PromptAgent.agent();
|
|
60
|
+
* promptAgent.nextAnswer("toto");
|
|
61
|
+
*
|
|
62
|
+
* const input = await question("what is your name?");
|
|
63
|
+
* assert.equal(input, "toto");
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
nextAnswer(value: string | boolean | Array<string | boolean>): void
|
|
67
|
+
}
|
package/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import { ConfirmPrompt } from "./src/confirm-prompt.js";
|
|
|
3
3
|
import { SelectPrompt } from "./src/select-prompt.js";
|
|
4
4
|
import { QuestionPrompt } from "./src/question-prompt.js";
|
|
5
5
|
import { required } from "./src/validators.js";
|
|
6
|
+
import { PromptAgent } from "./src/prompt-agent.js";
|
|
6
7
|
|
|
7
8
|
export async function question(message, options = {}) {
|
|
8
9
|
const questionPrompt = new QuestionPrompt(message, options);
|
|
@@ -22,4 +23,4 @@ export async function confirm(message, options) {
|
|
|
22
23
|
return confirmPrompt.confirm();
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
export { required };
|
|
26
|
+
export { required, PromptAgent };
|
package/package.json
CHANGED
package/src/abstract-prompt.js
CHANGED
|
@@ -5,6 +5,9 @@ import { createInterface } from "node:readline";
|
|
|
5
5
|
// Import Third-party Dependencies
|
|
6
6
|
import stripAnsi from "strip-ansi";
|
|
7
7
|
|
|
8
|
+
// Import Internal Dependencies
|
|
9
|
+
import { PromptAgent } from "./prompt-agent.js";
|
|
10
|
+
|
|
8
11
|
export class AbstractPrompt {
|
|
9
12
|
constructor(message, input = process.stdin, output = process.stdout) {
|
|
10
13
|
if (this.constructor === AbstractPrompt) {
|
|
@@ -19,6 +22,7 @@ export class AbstractPrompt {
|
|
|
19
22
|
this.stdout = output;
|
|
20
23
|
this.message = message;
|
|
21
24
|
this.history = [];
|
|
25
|
+
this.agent = PromptAgent.agent();
|
|
22
26
|
|
|
23
27
|
if (this.stdout.isTTY) {
|
|
24
28
|
this.stdin.setRawMode(true);
|
package/src/confirm-prompt.js
CHANGED
|
@@ -98,6 +98,15 @@ export class ConfirmPrompt extends AbstractPrompt {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
async confirm() {
|
|
101
|
+
if (this.agent.nextAnswers.length > 0) {
|
|
102
|
+
const answer = this.agent.nextAnswers.shift();
|
|
103
|
+
this.selectedValue = answer;
|
|
104
|
+
this.#onQuestionAnswer();
|
|
105
|
+
this.destroy();
|
|
106
|
+
|
|
107
|
+
return answer;
|
|
108
|
+
}
|
|
109
|
+
|
|
101
110
|
this.write(SYMBOLS.HideCursor);
|
|
102
111
|
|
|
103
112
|
try {
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// CONSTANTS
|
|
2
|
+
const kPrivateInstancier = Symbol("instancier");
|
|
3
|
+
|
|
4
|
+
export class PromptAgent {
|
|
5
|
+
/**
|
|
6
|
+
* The prompts answers queue.
|
|
7
|
+
* When not empty, any prompt will be answered by the first answer in this list.
|
|
8
|
+
*
|
|
9
|
+
* @type {string[]}
|
|
10
|
+
*/
|
|
11
|
+
nextAnswers = [];
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The shared PromptAgent.
|
|
15
|
+
*
|
|
16
|
+
* @type {PromptAgent}
|
|
17
|
+
*/
|
|
18
|
+
static #this;
|
|
19
|
+
|
|
20
|
+
static agent() {
|
|
21
|
+
// eslint-disable-next-line no-return-assign
|
|
22
|
+
return this.#this ??= new PromptAgent(kPrivateInstancier);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
constructor(instancier) {
|
|
26
|
+
if (instancier !== kPrivateInstancier) {
|
|
27
|
+
throw new Error("Cannot instanciate PromptAgent, use PromptAgent.agent() instead");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Programmatically set the next answer for any prompt (`question()`, `confirm()`, `select()`)
|
|
33
|
+
*
|
|
34
|
+
* This is useful for testing.
|
|
35
|
+
*
|
|
36
|
+
* @param {string | boolean | Array<string | boolean>} value
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```js
|
|
40
|
+
* const promptAgent = PromptAgent.agent();
|
|
41
|
+
* promptAgent.nextAnswer("toto");
|
|
42
|
+
*
|
|
43
|
+
* const input = await question("what is your name?");
|
|
44
|
+
* assert.equal(input, "toto");
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
nextAnswer(value) {
|
|
48
|
+
if (Array.isArray(value)) {
|
|
49
|
+
this.nextAnswers.push(...value);
|
|
50
|
+
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
this.nextAnswers.push(value);
|
|
55
|
+
}
|
|
56
|
+
}
|
package/src/question-prompt.js
CHANGED
|
@@ -76,6 +76,14 @@ export class QuestionPrompt extends AbstractPrompt {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
async question() {
|
|
79
|
+
if (this.agent.nextAnswers.length > 0) {
|
|
80
|
+
this.answer = this.agent.nextAnswers.shift();
|
|
81
|
+
this.#writeAnswer();
|
|
82
|
+
this.destroy();
|
|
83
|
+
|
|
84
|
+
return this.answer;
|
|
85
|
+
}
|
|
86
|
+
|
|
79
87
|
this.answer = await this.#question();
|
|
80
88
|
|
|
81
89
|
if (this.answer === "" && this.defaultValue) {
|
package/src/select-prompt.js
CHANGED
|
@@ -114,6 +114,14 @@ export class SelectPrompt extends AbstractPrompt {
|
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
async select() {
|
|
117
|
+
if (this.agent.nextAnswers.length > 0) {
|
|
118
|
+
const answer = this.agent.nextAnswers.shift();
|
|
119
|
+
this.#showAnsweredQuestion(answer);
|
|
120
|
+
this.destroy();
|
|
121
|
+
|
|
122
|
+
return answer;
|
|
123
|
+
}
|
|
124
|
+
|
|
117
125
|
this.write(SYMBOLS.HideCursor);
|
|
118
126
|
this.#showQuestion();
|
|
119
127
|
|