@topcli/prompts 1.1.0 → 1.2.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 +7 -11
- package/index.d.ts +8 -2
- package/package.json +7 -6
- package/src/confirm-prompt.js +69 -23
package/README.md
CHANGED
|
@@ -27,20 +27,15 @@ $ yarn add @topcli/prompts
|
|
|
27
27
|
You can locally run `node ./demo.js`
|
|
28
28
|
|
|
29
29
|
```js
|
|
30
|
-
import {
|
|
30
|
+
import { question, confirm, select } from "@topcli/prompts";
|
|
31
31
|
|
|
32
|
-
const kTestRunner = [
|
|
32
|
+
const kTestRunner = ["node", "tap", "tape", "vitest", "mocha", "ava"];
|
|
33
33
|
|
|
34
|
-
const name = await
|
|
35
|
-
const runner = await select(
|
|
36
|
-
|
|
37
|
-
maxVisible: 5
|
|
38
|
-
});
|
|
39
|
-
const isCLI = await confirm('Your project is a CLI ?', {
|
|
40
|
-
initial: true
|
|
41
|
-
});
|
|
34
|
+
const name = await question("Project name ?", { defaultValue: "foo" });
|
|
35
|
+
const runner = await select("Choose a test runner", { choices: kTestRunner, maxVisible: 5 });
|
|
36
|
+
const isCLI = await confirm("Your project is a CLI ?", { initial: true });
|
|
42
37
|
|
|
43
|
-
console.log(name, runner, isCLI)
|
|
38
|
+
console.log(name, runner, isCLI);
|
|
44
39
|
```
|
|
45
40
|
|
|
46
41
|
## API
|
|
@@ -141,6 +136,7 @@ export interface ConfirmOptions {
|
|
|
141
136
|
<td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/thomas-gentilhomme/"><img src="https://avatars.githubusercontent.com/u/4438263?v=4?s=100" width="100px;" alt="Gentilhomme"/><br /><sub><b>Gentilhomme</b></sub></a><br /><a href="https://github.com/TopCli/prompts/pulls?q=is%3Apr+reviewed-by%3Afraxken" title="Reviewed Pull Requests">👀</a></td>
|
|
142
137
|
<td align="center" valign="top" width="14.28%"><a href="http://tonygo.dev"><img src="https://avatars0.githubusercontent.com/u/22824417?v=4?s=100" width="100px;" alt="Tony Gorez"/><br /><sub><b>Tony Gorez</b></sub></a><br /><a href="https://github.com/TopCli/prompts/pulls?q=is%3Apr+reviewed-by%3Atony-go" title="Reviewed Pull Requests">👀</a></td>
|
|
143
138
|
<td align="center" valign="top" width="14.28%"><a href="http://sofiand.github.io/portfolio-client/"><img src="https://avatars.githubusercontent.com/u/39944043?v=4?s=100" width="100px;" alt="Yefis"/><br /><sub><b>Yefis</b></sub></a><br /><a href="https://github.com/TopCli/prompts/commits?author=SofianD" title="Code">💻</a> <a href="https://github.com/TopCli/prompts/commits?author=SofianD" title="Documentation">📖</a></td>
|
|
139
|
+
<td align="center" valign="top" width="14.28%"><a href="http://justie.dev"><img src="https://avatars.githubusercontent.com/u/7118300?v=4?s=100" width="100px;" alt="Ben"/><br /><sub><b>Ben</b></sub></a><br /><a href="https://github.com/TopCli/prompts/commits?author=JUSTIVE" title="Documentation">📖</a> <a href="#maintenance-JUSTIVE" title="Maintenance">🚧</a></td>
|
|
144
140
|
</tr>
|
|
145
141
|
</tbody>
|
|
146
142
|
</table>
|
package/index.d.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
export interface
|
|
1
|
+
export interface QuestionOptions {
|
|
2
|
+
stdin?: NodeJS.ReadStream & {
|
|
3
|
+
fd: 0;
|
|
4
|
+
};
|
|
5
|
+
stdout?: NodeJS.WriteStream & {
|
|
6
|
+
fd: 1;
|
|
7
|
+
};
|
|
2
8
|
defaultValue?: string;
|
|
3
9
|
validators?: Validator[];
|
|
4
10
|
}
|
|
@@ -24,7 +30,7 @@ export interface ConfirmOptions {
|
|
|
24
30
|
initial?: boolean;
|
|
25
31
|
}
|
|
26
32
|
|
|
27
|
-
export function question(message: string, options?:
|
|
33
|
+
export function question(message: string, options?: QuestionOptions): Promise<string>;
|
|
28
34
|
export function select(message: string, options: SelectOptions): Promise<string>;
|
|
29
35
|
export function confirm(message: string, options?: ConfirmOptions): Promise<boolean>;
|
|
30
36
|
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@topcli/prompts",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Node.js user input library for command-line interfaces.",
|
|
5
5
|
"scripts": {
|
|
6
|
-
"test": "node --loader=esmock --test test/",
|
|
6
|
+
"test": "node --no-warnings=ExperimentalWarning --loader=esmock --test test/",
|
|
7
7
|
"coverage": "c8 -r html npm run test",
|
|
8
8
|
"lint": "eslint .",
|
|
9
9
|
"lint:fix": "eslint . --fix"
|
|
@@ -24,14 +24,15 @@
|
|
|
24
24
|
"type": "module",
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@nodesecure/eslint-config": "^1.7.0",
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
27
|
+
"@types/node": "^20.4.5",
|
|
28
|
+
"c8": "^8.0.0",
|
|
29
|
+
"eslint": "^8.44.0",
|
|
30
|
+
"esmock": "^2.3.1"
|
|
30
31
|
},
|
|
31
32
|
"dependencies": {
|
|
32
33
|
"is-unicode-supported": "^1.3.0",
|
|
33
34
|
"kleur": "^4.1.5",
|
|
34
|
-
"strip-ansi": "^7.0
|
|
35
|
+
"strip-ansi": "^7.1.0"
|
|
35
36
|
},
|
|
36
37
|
"engines": {
|
|
37
38
|
"node": ">=14"
|
package/src/confirm-prompt.js
CHANGED
|
@@ -8,7 +8,25 @@ import kleur from "kleur";
|
|
|
8
8
|
import { AbstractPrompt } from "./abstract-prompt.js";
|
|
9
9
|
import { SYMBOLS } from "./constants.js";
|
|
10
10
|
|
|
11
|
+
// CONSTANTS
|
|
12
|
+
const kToggleKeys = new Set([
|
|
13
|
+
"left",
|
|
14
|
+
"right",
|
|
15
|
+
"tab",
|
|
16
|
+
"q",
|
|
17
|
+
"a",
|
|
18
|
+
"d",
|
|
19
|
+
"h",
|
|
20
|
+
"j",
|
|
21
|
+
"k",
|
|
22
|
+
"l",
|
|
23
|
+
"space"
|
|
24
|
+
]);
|
|
25
|
+
|
|
11
26
|
export class ConfirmPrompt extends AbstractPrompt {
|
|
27
|
+
#boundKeyPressEvent;
|
|
28
|
+
#boundExitEvent;
|
|
29
|
+
|
|
12
30
|
constructor(message, options = {}) {
|
|
13
31
|
const {
|
|
14
32
|
stdin = process.stdin,
|
|
@@ -17,55 +35,83 @@ export class ConfirmPrompt extends AbstractPrompt {
|
|
|
17
35
|
} = options;
|
|
18
36
|
super(message, stdin, stdout);
|
|
19
37
|
|
|
20
|
-
const Yes = kleur.bold("Yes");
|
|
21
|
-
const No = kleur.bold("No");
|
|
22
|
-
this.tip = kleur.gray(initial ? `(${Yes}/no)` : `(yes/${No})`);
|
|
23
|
-
|
|
24
38
|
this.initial = initial;
|
|
39
|
+
this.selectedValue = initial;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
#getHint() {
|
|
43
|
+
const Yes = kleur.bold().underline().cyan("Yes");
|
|
44
|
+
const No = kleur.bold().underline().cyan("No");
|
|
45
|
+
|
|
46
|
+
return this.selectedValue ? `${Yes}/No` : `Yes/${No}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
#render() {
|
|
50
|
+
this.write(this.#getQuestionQuery());
|
|
25
51
|
}
|
|
26
52
|
|
|
27
53
|
#question() {
|
|
28
54
|
return new Promise((resolve) => {
|
|
29
55
|
const questionQuery = this.#getQuestionQuery();
|
|
30
56
|
|
|
31
|
-
this.
|
|
32
|
-
|
|
33
|
-
|
|
57
|
+
this.write(questionQuery);
|
|
58
|
+
|
|
59
|
+
this.#boundKeyPressEvent = this.#onKeypress.bind(this, resolve);
|
|
60
|
+
this.stdin.on("keypress", this.#boundKeyPressEvent);
|
|
34
61
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
);
|
|
62
|
+
this.#boundExitEvent = this.#onProcessExit.bind(this);
|
|
63
|
+
process.once("exit", this.#boundExitEvent);
|
|
38
64
|
});
|
|
39
65
|
}
|
|
40
66
|
|
|
67
|
+
#onKeypress(resolve, value, key) {
|
|
68
|
+
this.stdin.pause();
|
|
69
|
+
this.stdout.moveCursor(-this.#getQuestionQuery().length, 0);
|
|
70
|
+
this.stdout.clearScreenDown(() => this.stdin.resume());
|
|
71
|
+
|
|
72
|
+
if (key.name === "return") {
|
|
73
|
+
resolve(this.selectedValue);
|
|
74
|
+
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (kToggleKeys.has(key.name)) {
|
|
79
|
+
this.selectedValue = !this.selectedValue;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
this.#render();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
#onProcessExit() {
|
|
86
|
+
this.stdin.off("keypress", this.#boundKeyPressEvent);
|
|
87
|
+
}
|
|
88
|
+
|
|
41
89
|
#getQuestionQuery() {
|
|
42
90
|
const query = kleur.bold(`${SYMBOLS.QuestionMark} ${this.message}`);
|
|
43
91
|
|
|
44
|
-
return `${query} ${this
|
|
92
|
+
return `${query} ${this.#getHint()}`;
|
|
45
93
|
}
|
|
46
94
|
|
|
47
95
|
#onQuestionAnswer() {
|
|
48
96
|
this.clearLastLine();
|
|
49
|
-
this.write(`${this.
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
#validateResult(result) {
|
|
53
|
-
if (typeof result !== "string") {
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return ["y", "yes", "no", "n"].includes(result.toLowerCase());
|
|
97
|
+
this.write(`${this.selectedValue ? SYMBOLS.Tick : SYMBOLS.Cross} ${kleur.bold(this.message)}${EOL}`);
|
|
58
98
|
}
|
|
59
99
|
|
|
60
100
|
async confirm() {
|
|
101
|
+
this.write(SYMBOLS.HideCursor);
|
|
102
|
+
|
|
61
103
|
try {
|
|
62
|
-
|
|
63
|
-
this.answer = this.#validateResult(result) ? ["y", "yes"].includes(result.toLocaleLowerCase()) : this.initial;
|
|
104
|
+
await this.#question();
|
|
64
105
|
this.#onQuestionAnswer();
|
|
65
106
|
|
|
66
|
-
return this.
|
|
107
|
+
return this.selectedValue;
|
|
67
108
|
}
|
|
68
109
|
finally {
|
|
110
|
+
this.write(SYMBOLS.ShowCursor);
|
|
111
|
+
|
|
112
|
+
this.#onProcessExit();
|
|
113
|
+
process.off("exit", this.#boundExitEvent);
|
|
114
|
+
|
|
69
115
|
this.destroy();
|
|
70
116
|
}
|
|
71
117
|
}
|