@topcli/prompts 2.0.0 → 2.1.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/LICENSE CHANGED
@@ -1,13 +1,13 @@
1
- Copyright 2023-2024 TopCli
2
-
3
- Permission to use, copy, modify, and/or distribute this software for any purpose
4
- with or without fee is hereby granted, provided that the above copyright notice
5
- and this permission notice appear in all copies.
6
-
7
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
8
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
9
- FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
10
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
11
- OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
12
- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
13
- THIS SOFTWARE.
1
+ Copyright 2023-2025 TopCli
2
+
3
+ Permission to use, copy, modify, and/or distribute this software for any purpose
4
+ with or without fee is hereby granted, provided that the above copyright notice
5
+ and this permission notice appear in all copies.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
8
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
9
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
10
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
11
+ OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
12
+ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
13
+ THIS SOFTWARE.
package/README.md CHANGED
@@ -1,264 +1,274 @@
1
- <div align="center">
2
- <img src="./public/banner.png" alt="@topcli/prompts">
3
-
4
- ![version](https://img.shields.io/badge/dynamic/json.svg?style=for-the-badge&url=https://raw.githubusercontent.com/TopCli/prompts/main/package.json&query=$.version&label=Version)
5
- [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg?style=for-the-badge)](https://github.com/TopCli/prompts/commit-activity)
6
- [![isc](https://img.shields.io/badge/License-ISC-blue.svg?style=for-the-badge)](https://github.com/TopCli/prompts/blob/main/LICENSE)
7
- [![scorecard](https://api.securityscorecards.dev/projects/github.com/TopCli/prompts/badge?style=for-the-badge)](https://ossf.github.io/scorecard-visualizer/#/projects/github.com/TopCli/prompts)
8
- ![build](https://img.shields.io/github/actions/workflow/status/TopCli/prompts/node.js.yml?style=for-the-badge)
9
-
10
- <img src="./public/topcli.gif" alt="demo">
11
- </div>
12
-
13
- ## Requirements
14
- - [Node.js](https://nodejs.org/en/) v18 or higher
15
-
16
- ## Getting Started
17
-
18
- This package is available in the Node Package Repository and can be easily installed with [npm](https://docs.npmjs.com/getting-started/what-is-npm) or [yarn](https://yarnpkg.com).
19
-
20
- ```bash
21
- $ npm i @topcli/prompts
22
- # or
23
- $ yarn add @topcli/prompts
24
- ```
25
-
26
- ## Usage exemple
27
-
28
- You can locally run `node ./demo.js`
29
-
30
- ```js
31
- import { question, confirm, select, multiselect } from "@topcli/prompts";
32
-
33
- const kTestRunner = ["node", "tap", "tape", "vitest", "mocha", "ava"];
34
-
35
- const name = await question("Project name ?", { defaultValue: "foo" });
36
- const runner = await select("Choose a test runner", { choices: kTestRunner, maxVisible: 5 });
37
- const isCLI = await confirm("Your project is a CLI ?", { initial: true });
38
- const os = await multiselect("Choose OS", {
39
- choices: ["linux", "mac", "windows"],
40
- preSelectedChoices: ["linux"]
41
- });
42
-
43
- console.log(name, runner, isCLI, os);
44
- ```
45
-
46
- ## API
47
-
48
- ### `question()`
49
-
50
- ```ts
51
- question(message: string, options?: PromptOptions): Promise<string>
52
- ```
53
-
54
- Simple prompt, similar to `rl.question()` with an improved UI.
55
-
56
- Use `options.secure` if you need to hide both input and answer.
57
-
58
- Use `options.signal` to set an `AbortSignal` (throws a [AbortError](#aborterror)).
59
-
60
- Use `options.validators` to handle user input.
61
-
62
- **Example**
63
-
64
- ```js
65
- const packageName = await question('Package name', {
66
- validators: [
67
- {
68
- validate: (value) => {
69
- if (!existsSync(join(process.cwd(), value))) {
70
- return `Folder ${value} already exists`
71
- }
72
- }
73
- }
74
- ]
75
- });
76
- ```
77
-
78
- **This package provide some validators for common usage**
79
-
80
- - required
81
-
82
- ```js
83
- import { prompt, required } from "@topcli/prompts";
84
-
85
- const name = await prompt("What's your name ?", {
86
- validators: [required()]
87
- });
88
- ```
89
-
90
- ### `select()`
91
-
92
- ```ts
93
- select(message: string, options: SelectOptions): Promise<string>
94
- ```
95
-
96
- Scrollable select depending `maxVisible` (default `8`).
97
-
98
- Use `ignoreValues` to skip result render & clear lines after a selected one.
99
-
100
- Use `validators` to handle user input.
101
-
102
- Use `autocomplete` to allow filtered choices. This can be useful for a large list of choices.
103
-
104
- Use `caseSensitive` to make autocomplete filters case sensitive. Default `false`
105
-
106
- Use `options.signal` to set an `AbortSignal` (throws a [AbortError](#aborterror)).
107
-
108
- ### `multiselect()`
109
-
110
- ```ts
111
- multiselect(message: string, options: MultiselectOptions): Promise<[string]>
112
- ```
113
-
114
- Scrollable multiselect depending `maxVisible` (default `8`).<br>
115
- Use `preSelectedChoices` to pre-select choices.
116
-
117
- Use `validators` to handle user input.
118
-
119
- Use `showHint: false` to disable hint (this option is truthy by default).
120
-
121
- Use `autocomplete` to allow filtered choices. This can be useful for a large list of choices.
122
-
123
- Use `caseSensitive` to make autocomplete filters case sensitive. Default `false`.
124
-
125
- Use `options.signal` to set an `AbortSignal` (throws a [AbortError](#aborterror)).
126
-
127
- ### `confirm()`
128
-
129
- ```ts
130
- confirm(message: string, options?: ConfirmOptions): Promise<boolean>
131
- ```
132
-
133
- Boolean prompt, default to `options.initial` (`false`).
134
-
135
- > [!TIP]
136
- > You can answer pressing <kbd>Y</kbd> or <kbd>N</kbd>
137
-
138
- Use `options.signal` to set an `AbortSignal` (throws a [AbortError](#aborterror)).
139
-
140
- ### `PromptAgent`
141
-
142
- The `PromptAgent` class allows to programmatically set the next answers for any prompt function, this can be useful for testing.
143
-
144
- ```ts
145
- const agent = PromptAgent.agent();
146
- agent.nextAnswer("John");
147
-
148
- const input = await question("What's your name?");
149
- assert.equal(input, "John");
150
- ```
151
-
152
- > [!WARNING]
153
- > Answers set with `PromptAgent` will **bypass** any logical & validation rules.
154
- > Examples:
155
- > - When using `question()`, `validators` functions will not be executed.
156
- > - When using `select()`, the answer can be different from the available choices.
157
- > - When using `confirm()`, the answer can be any type other than boolean.
158
- > - etc<br>
159
- > **Use with caution**
160
-
161
- ## Errors
162
-
163
- ### `AbortError`
164
-
165
- ```ts
166
- export class AbortError extends Error {
167
- constructor(message: string) {
168
- super(message);
169
- this.name = "AbortError";
170
- }
171
- }
172
- ```
173
-
174
- ## Interfaces
175
-
176
- ```ts
177
- type Stdin = NodeJS.ReadStream & {
178
- fd: 0;
179
- };
180
-
181
- type Stdout = NodeJS.WriteStream & {
182
- fd: 1;
183
- }
184
-
185
- export interface AbstractPromptOptions {
186
- stdin?: Stdin;
187
- stdout?: Stdout;
188
- message: string;
189
- sginal?: AbortSignal;
190
- }
191
-
192
- export interface PromptValidator<T = string | string[] | boolean> {
193
- validate: (input: T) => boolean;
194
- error: (input: T) => string;
195
- }
196
-
197
- export interface QuestionOptions extends SharedOptions {
198
- defaultValue?: string;
199
- validators?: Validator[];
200
- secure?: boolean;
201
- }
202
-
203
- export interface Choice {
204
- value: any;
205
- label: string;
206
- description?: string;
207
- }
208
-
209
- export interface SelectOptions extends SharedOptions {
210
- choices: (Choice | string)[];
211
- maxVisible?: number;
212
- ignoreValues?: (string | number | boolean)[];
213
- validators?: Validator[];
214
- autocomplete?: boolean;
215
- caseSensitive?: boolean;
216
- }
217
-
218
- export interface MultiselectOptions extends SharedOptions {
219
- choices: (Choice | string)[];
220
- maxVisible?: number;
221
- preSelectedChoices?: (Choice | string)[];
222
- validators?: Validator[];
223
- autocomplete?: boolean;
224
- caseSensitive?: boolean;
225
- showHint?: boolean;
226
- }
227
-
228
- export interface ConfirmOptions extends SharedOptions {
229
- initial?: boolean;
230
- }
231
- ```
232
-
233
- ## Contributing
234
-
235
- Please read [CONTRIBUTING.md](./CONTRIBUTING.md) for details on our code of conduct, and the process for submitting pull requests to us.
236
-
237
- Open an issue if you want to provide feedback such as bug reports or enchancements.
238
-
239
- ## Contributors
240
-
241
- <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
242
- <!-- prettier-ignore-start -->
243
- <!-- markdownlint-disable -->
244
- <table>
245
- <tbody>
246
- <tr>
247
- <td align="center" valign="top" width="14.28%"><a href="https://github.com/PierreDemailly"><img src="https://avatars.githubusercontent.com/u/39910767?v=4?s=100" width="100px;" alt="PierreDemailly"/><br /><sub><b>PierreDemailly</b></sub></a><br /><a href="https://github.com/TopCli/prompts/commits?author=PierreDemailly" title="Code">💻</a> <a href="https://github.com/TopCli/prompts/commits?author=PierreDemailly" title="Tests">⚠️</a></td>
248
- <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> <a href="https://github.com/TopCli/prompts/commits?author=fraxken" title="Code">💻</a> <a href="https://github.com/TopCli/prompts/commits?author=fraxken" title="Documentation">📖</a></td>
249
- <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>
250
- <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>
251
- <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>
252
- <td align="center" valign="top" width="14.28%"><a href="https://github.com/ncukondo"><img src="https://avatars.githubusercontent.com/u/17022138?v=4?s=100" width="100px;" alt="Takeshi Kondo"/><br /><sub><b>Takeshi Kondo</b></sub></a><br /><a href="#maintenance-ncukondo" title="Maintenance">🚧</a></td>
253
- <td align="center" valign="top" width="14.28%"><a href="https://github.com/FredGuiou"><img src="https://avatars.githubusercontent.com/u/99122562?v=4?s=100" width="100px;" alt="FredGuiou"/><br /><sub><b>FredGuiou</b></sub></a><br /><a href="https://github.com/TopCli/prompts/commits?author=FredGuiou" title="Code">💻</a> <a href="https://github.com/TopCli/prompts/commits?author=FredGuiou" title="Tests">⚠️</a> <a href="https://github.com/TopCli/prompts/commits?author=FredGuiou" title="Documentation">📖</a></td>
254
- </tr>
255
- <tr>
256
- <td align="center" valign="top" width="14.28%"><a href="https://github.com/noxify"><img src="https://avatars.githubusercontent.com/u/521777?v=4?s=100" width="100px;" alt="Marcus Reinhardt"/><br /><sub><b>Marcus Reinhardt</b></sub></a><br /><a href="https://github.com/TopCli/prompts/commits?author=noxify" title="Code">💻</a> <a href="https://github.com/TopCli/prompts/commits?author=noxify" title="Tests">⚠️</a> <a href="https://github.com/TopCli/prompts/commits?author=noxify" title="Documentation">📖</a></td>
257
- </tr>
258
- </tbody>
259
- </table>
260
-
261
- <!-- markdownlint-restore -->
262
- <!-- prettier-ignore-end -->
263
-
264
- <!-- ALL-CONTRIBUTORS-LIST:END -->
1
+ <div align="center">
2
+ <img src="./public/banner.png" alt="@topcli/prompts">
3
+
4
+ ![version](https://img.shields.io/badge/dynamic/json.svg?style=for-the-badge&url=https://raw.githubusercontent.com/TopCli/prompts/main/package.json&query=$.version&label=Version)
5
+ [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg?style=for-the-badge)](https://github.com/TopCli/prompts/commit-activity)
6
+ [![isc](https://img.shields.io/badge/License-ISC-blue.svg?style=for-the-badge)](https://github.com/TopCli/prompts/blob/main/LICENSE)
7
+ [![scorecard](https://api.securityscorecards.dev/projects/github.com/TopCli/prompts/badge?style=for-the-badge)](https://ossf.github.io/scorecard-visualizer/#/projects/github.com/TopCli/prompts)
8
+ ![build](https://img.shields.io/github/actions/workflow/status/TopCli/prompts/node.js.yml?style=for-the-badge)
9
+
10
+ <img src="./public/topcli.gif" alt="demo">
11
+ </div>
12
+
13
+ ## Requirements
14
+ - [Node.js](https://nodejs.org/en/) v20 or higher
15
+
16
+ ## Getting Started
17
+
18
+ This package is available in the Node Package Repository and can be easily installed with [npm](https://docs.npmjs.com/getting-started/what-is-npm) or [yarn](https://yarnpkg.com).
19
+
20
+ ```bash
21
+ $ npm i @topcli/prompts
22
+ # or
23
+ $ yarn add @topcli/prompts
24
+ ```
25
+
26
+ ## Usage exemple
27
+
28
+ You can locally run `node ./demo.js`
29
+
30
+ ```js
31
+ import { question, confirm, select, multiselect } from "@topcli/prompts";
32
+
33
+ const kTestRunner = ["node", "tap", "tape", "vitest", "mocha", "ava"];
34
+
35
+ const name = await question("Project name ?", { defaultValue: "foo" });
36
+ const runner = await select("Choose a test runner", { choices: kTestRunner, maxVisible: 5 });
37
+ const isCLI = await confirm("Your project is a CLI ?", { initial: true });
38
+ const os = await multiselect("Choose OS", {
39
+ choices: ["linux", "mac", "windows"],
40
+ preSelectedChoices: ["linux"]
41
+ });
42
+
43
+ console.log(name, runner, isCLI, os);
44
+ ```
45
+
46
+ ## API
47
+
48
+ ### `question()`
49
+
50
+ ```ts
51
+ question(message: string, options?: PromptOptions): Promise<string>
52
+ ```
53
+
54
+ Simple prompt, similar to `rl.question()` with an improved UI.
55
+
56
+ Use `options.defaultValue` to set a default value.
57
+
58
+ Use `options.secure` if you need to hide both input and answer.
59
+
60
+ Use `options.signal` to set an `AbortSignal` (throws a [AbortError](#aborterror)).
61
+
62
+ Use `options.validators` to handle user input.
63
+
64
+ Use `options.skip` to skip prompt. It will return `options.defaultValue` if given, `""` otherwise.
65
+
66
+ **Example**
67
+
68
+ ```js
69
+ const packageName = await question('Package name', {
70
+ validators: [
71
+ {
72
+ validate: (value) => {
73
+ if (!existsSync(join(process.cwd(), value))) {
74
+ return `Folder ${value} already exists`
75
+ }
76
+ }
77
+ }
78
+ ]
79
+ });
80
+ ```
81
+
82
+ **This package provide some validators for common usage**
83
+
84
+ - required
85
+
86
+ ```js
87
+ import { prompt, required } from "@topcli/prompts";
88
+
89
+ const name = await prompt("What's your name ?", {
90
+ validators: [required()]
91
+ });
92
+ ```
93
+
94
+ ### `select()`
95
+
96
+ ```ts
97
+ select(message: string, options: SelectOptions): Promise<string>
98
+ ```
99
+
100
+ Scrollable select depending `maxVisible` (default `8`).
101
+
102
+ Use `options.ignoreValues` to skip result render & clear lines after a selected one.
103
+
104
+ Use `options.validators` to handle user input.
105
+
106
+ Use `options.autocomplete` to allow filtered choices. This can be useful for a large list of choices.
107
+
108
+ Use `options.caseSensitive` to make autocomplete filters case sensitive. Default `false`
109
+
110
+ Use `options.signal` to set an `AbortSignal` (throws a [AbortError](#aborterror)).
111
+
112
+ Use `options.skip` to skip prompt. It will return the first choice.
113
+
114
+ ### `multiselect()`
115
+
116
+ ```ts
117
+ multiselect(message: string, options: MultiselectOptions): Promise<[string]>
118
+ ```
119
+
120
+ Scrollable multiselect depending `options.maxVisible` (default `8`).<br>
121
+ Use `options.preSelectedChoices` to pre-select choices.
122
+
123
+ Use `options.validators` to handle user input.
124
+
125
+ Use `options.showHint: false` to disable hint (this option is truthy by default).
126
+
127
+ Use `options.autocomplete` to allow filtered choices. This can be useful for a large list of choices.
128
+
129
+ Use `options.caseSensitive` to make autocomplete filters case sensitive. Default `false`.
130
+
131
+ Use `options.signal` to set an `AbortSignal` (throws a [AbortError](#aborterror)).
132
+
133
+ Use `options.skip` to skip prompt. It will return `options.preSelectedChoices` if given, `[]` otherwise.
134
+
135
+ ### `confirm()`
136
+
137
+ ```ts
138
+ confirm(message: string, options?: ConfirmOptions): Promise<boolean>
139
+ ```
140
+
141
+ Boolean prompt, default to `options.initial` (`false`).
142
+
143
+ > [!TIP]
144
+ > You can answer pressing <kbd>Y</kbd> or <kbd>N</kbd>
145
+
146
+ Use `options.signal` to set an `AbortSignal` (throws a [AbortError](#aborterror)).
147
+
148
+ Use `options.skip` to skip prompt. It will return `options.initial` (`false` by default)
149
+
150
+ ### `PromptAgent`
151
+
152
+ The `PromptAgent` class allows to programmatically set the next answers for any prompt function, this can be useful for testing.
153
+
154
+ ```ts
155
+ const agent = PromptAgent.agent();
156
+ agent.nextAnswer("John");
157
+
158
+ const input = await question("What's your name?");
159
+ assert.equal(input, "John");
160
+ ```
161
+
162
+ > [!WARNING]
163
+ > Answers set with `PromptAgent` will **bypass** any logical & validation rules.
164
+ > Examples:
165
+ > - When using `question()`, `validators` functions will not be executed.
166
+ > - When using `select()`, the answer can be different from the available choices.
167
+ > - When using `confirm()`, the answer can be any type other than boolean.
168
+ > - etc<br>
169
+ > **Use with caution**
170
+
171
+ ## Errors
172
+
173
+ ### `AbortError`
174
+
175
+ ```ts
176
+ export class AbortError extends Error {
177
+ constructor(message: string) {
178
+ super(message);
179
+ this.name = "AbortError";
180
+ }
181
+ }
182
+ ```
183
+
184
+ ## Interfaces
185
+
186
+ ```ts
187
+ type Stdin = NodeJS.ReadStream & {
188
+ fd: 0;
189
+ };
190
+
191
+ type Stdout = NodeJS.WriteStream & {
192
+ fd: 1;
193
+ }
194
+
195
+ export interface AbstractPromptOptions {
196
+ stdin?: Stdin;
197
+ stdout?: Stdout;
198
+ message: string;
199
+ sginal?: AbortSignal;
200
+ }
201
+
202
+ export interface PromptValidator<T = string | string[] | boolean> {
203
+ validate: (input: T) => boolean;
204
+ error: (input: T) => string;
205
+ }
206
+
207
+ export interface QuestionOptions extends SharedOptions {
208
+ defaultValue?: string;
209
+ validators?: Validator[];
210
+ secure?: boolean;
211
+ }
212
+
213
+ export interface Choice {
214
+ value: any;
215
+ label: string;
216
+ description?: string;
217
+ }
218
+
219
+ export interface SelectOptions extends SharedOptions {
220
+ choices: (Choice | string)[];
221
+ maxVisible?: number;
222
+ ignoreValues?: (string | number | boolean)[];
223
+ validators?: Validator[];
224
+ autocomplete?: boolean;
225
+ caseSensitive?: boolean;
226
+ }
227
+
228
+ export interface MultiselectOptions extends SharedOptions {
229
+ choices: (Choice | string)[];
230
+ maxVisible?: number;
231
+ preSelectedChoices?: (Choice | string)[];
232
+ validators?: Validator[];
233
+ autocomplete?: boolean;
234
+ caseSensitive?: boolean;
235
+ showHint?: boolean;
236
+ }
237
+
238
+ export interface ConfirmOptions extends SharedOptions {
239
+ initial?: boolean;
240
+ }
241
+ ```
242
+
243
+ ## Contributing
244
+
245
+ Please read [CONTRIBUTING.md](./CONTRIBUTING.md) for details on our code of conduct, and the process for submitting pull requests to us.
246
+
247
+ Open an issue if you want to provide feedback such as bug reports or enchancements.
248
+
249
+ ## Contributors
250
+
251
+ <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
252
+ <!-- prettier-ignore-start -->
253
+ <!-- markdownlint-disable -->
254
+ <table>
255
+ <tbody>
256
+ <tr>
257
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/PierreDemailly"><img src="https://avatars.githubusercontent.com/u/39910767?v=4?s=100" width="100px;" alt="PierreDemailly"/><br /><sub><b>PierreDemailly</b></sub></a><br /><a href="https://github.com/TopCli/prompts/commits?author=PierreDemailly" title="Code">💻</a> <a href="https://github.com/TopCli/prompts/commits?author=PierreDemailly" title="Tests">⚠️</a></td>
258
+ <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> <a href="https://github.com/TopCli/prompts/commits?author=fraxken" title="Code">💻</a> <a href="https://github.com/TopCli/prompts/commits?author=fraxken" title="Documentation">📖</a></td>
259
+ <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>
260
+ <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>
261
+ <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>
262
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/ncukondo"><img src="https://avatars.githubusercontent.com/u/17022138?v=4?s=100" width="100px;" alt="Takeshi Kondo"/><br /><sub><b>Takeshi Kondo</b></sub></a><br /><a href="#maintenance-ncukondo" title="Maintenance">🚧</a></td>
263
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/FredGuiou"><img src="https://avatars.githubusercontent.com/u/99122562?v=4?s=100" width="100px;" alt="FredGuiou"/><br /><sub><b>FredGuiou</b></sub></a><br /><a href="https://github.com/TopCli/prompts/commits?author=FredGuiou" title="Code">💻</a> <a href="https://github.com/TopCli/prompts/commits?author=FredGuiou" title="Tests">⚠️</a> <a href="https://github.com/TopCli/prompts/commits?author=FredGuiou" title="Documentation">📖</a></td>
264
+ </tr>
265
+ <tr>
266
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/noxify"><img src="https://avatars.githubusercontent.com/u/521777?v=4?s=100" width="100px;" alt="Marcus Reinhardt"/><br /><sub><b>Marcus Reinhardt</b></sub></a><br /><a href="https://github.com/TopCli/prompts/commits?author=noxify" title="Code">💻</a> <a href="https://github.com/TopCli/prompts/commits?author=noxify" title="Tests">⚠️</a> <a href="https://github.com/TopCli/prompts/commits?author=noxify" title="Documentation">📖</a></td>
267
+ </tr>
268
+ </tbody>
269
+ </table>
270
+
271
+ <!-- markdownlint-restore -->
272
+ <!-- prettier-ignore-end -->
273
+
274
+ <!-- ALL-CONTRIBUTORS-LIST:END -->
package/dist/index.cjs CHANGED
@@ -28,8 +28,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
 
30
30
  // index.ts
31
- var prompts_exports = {};
32
- __export(prompts_exports, {
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
33
  PromptAgent: () => PromptAgent,
34
34
  confirm: () => confirm,
35
35
  multiselect: () => multiselect,
@@ -37,7 +37,7 @@ __export(prompts_exports, {
37
37
  required: () => required,
38
38
  select: () => select
39
39
  });
40
- module.exports = __toCommonJS(prompts_exports);
40
+ module.exports = __toCommonJS(index_exports);
41
41
 
42
42
  // src/prompts/question.ts
43
43
  var import_node_os2 = require("os");
@@ -128,6 +128,7 @@ var AbstractPrompt = class _AbstractPrompt extends import_node_events.default {
128
128
  stdout;
129
129
  message;
130
130
  signal;
131
+ skip;
131
132
  history;
132
133
  agent;
133
134
  mute;
@@ -142,7 +143,8 @@ var AbstractPrompt = class _AbstractPrompt extends import_node_events.default {
142
143
  stdin: input = process.stdin,
143
144
  stdout: output = process.stdout,
144
145
  message,
145
- signal
146
+ signal,
147
+ skip = false
146
148
  } = options;
147
149
  if (typeof message !== "string") {
148
150
  throw new TypeError(`message must be string, ${typeof message} given.`);
@@ -157,6 +159,7 @@ var AbstractPrompt = class _AbstractPrompt extends import_node_events.default {
157
159
  this.stdout = output;
158
160
  this.message = message;
159
161
  this.signal = signal;
162
+ this.skip = skip;
160
163
  this.history = [];
161
164
  this.agent = PromptAgent.agent();
162
165
  this.mute = false;
@@ -340,7 +343,11 @@ var QuestionPrompt = class extends AbstractPrompt {
340
343
  this.answerBuffer = void 0;
341
344
  this.#writeAnswer();
342
345
  }
343
- question() {
346
+ async question() {
347
+ if (this.skip) {
348
+ this.destroy();
349
+ return this.defaultValue ?? "";
350
+ }
344
351
  return new Promise(async (resolve, reject) => {
345
352
  this.answer = this.agent.nextAnswers.shift();
346
353
  if (this.answer !== void 0) {
@@ -417,7 +424,7 @@ var ConfirmPrompt = class extends AbstractPrompt {
417
424
  process.once("exit", this.#boundExitEvent);
418
425
  });
419
426
  }
420
- #onKeypress(resolve, value, key) {
427
+ #onKeypress(resolve, _value, key) {
421
428
  this.stdout.moveCursor(
422
429
  -this.stdout.columns,
423
430
  -Math.floor((0, import_wcwidth2.default)(stripAnsi(this.#getQuestionQuery())) / this.stdout.columns)
@@ -459,7 +466,11 @@ var ConfirmPrompt = class extends AbstractPrompt {
459
466
  this.stdout.clearScreenDown();
460
467
  this.write(`${this.selectedValue ? SYMBOLS.Tick : SYMBOLS.Cross} ${(0, import_node_util3.styleText)("bold", this.message)}${import_node_os3.EOL}`);
461
468
  }
462
- confirm() {
469
+ async confirm() {
470
+ if (this.skip) {
471
+ this.destroy();
472
+ return this.initial;
473
+ }
463
474
  return new Promise(async (resolve, reject) => {
464
475
  const answer = this.agent.nextAnswers.shift();
465
476
  if (answer !== void 0) {
@@ -653,7 +664,12 @@ var SelectPrompt = class extends AbstractPrompt {
653
664
  render();
654
665
  }
655
666
  }
656
- select() {
667
+ async select() {
668
+ if (this.skip) {
669
+ this.destroy();
670
+ const answer = this.options.choices[0];
671
+ return typeof answer === "string" ? answer : answer.value;
672
+ }
657
673
  return new Promise((resolve, reject) => {
658
674
  const answer = this.agent.nextAnswers.shift();
659
675
  if (answer !== void 0) {
@@ -773,7 +789,7 @@ var MultiselectPrompt = class extends AbstractPrompt {
773
789
  constructor(options) {
774
790
  const {
775
791
  choices,
776
- preSelectedChoices,
792
+ preSelectedChoices = [],
777
793
  validators = [],
778
794
  showHint = true,
779
795
  ...baseOptions
@@ -797,9 +813,6 @@ var MultiselectPrompt = class extends AbstractPrompt {
797
813
  }
798
814
  }
799
815
  }
800
- if (!preSelectedChoices) {
801
- return;
802
- }
803
816
  for (const choice of preSelectedChoices) {
804
817
  const choiceIndex = this.filteredChoices.findIndex((item) => {
805
818
  if (typeof item === "string") {
@@ -864,6 +877,25 @@ var MultiselectPrompt = class extends AbstractPrompt {
864
877
  const formattedChoice = (0, import_node_util5.styleText)("yellow", choices);
865
878
  this.write(`${prefix}${choices ? ` ${formattedChoice}` : ""}${import_node_os5.EOL}`);
866
879
  }
880
+ #selectedChoices() {
881
+ return [...this.selectedIndexes].reduce(
882
+ (acc, index) => {
883
+ const choice = this.filteredChoices[index];
884
+ if (typeof choice === "string") {
885
+ acc.values.push(choice);
886
+ acc.labels.push(choice);
887
+ } else {
888
+ acc.values.push(choice.value);
889
+ acc.labels.push(choice.label);
890
+ }
891
+ return acc;
892
+ },
893
+ {
894
+ values: [],
895
+ labels: []
896
+ }
897
+ );
898
+ }
867
899
  #onProcessExit() {
868
900
  this.stdin.off("keypress", this.#boundKeyPressEvent);
869
901
  this.stdout.moveCursor(-this.stdout.columns, 0);
@@ -888,14 +920,7 @@ var MultiselectPrompt = class extends AbstractPrompt {
888
920
  this.selectedIndexes = new Set([...this.selectedIndexes].filter((index) => index !== this.activeIndex));
889
921
  render();
890
922
  } else if (key.name === "return") {
891
- const labels = [...this.selectedIndexes].map((index) => {
892
- const choice = this.filteredChoices[index];
893
- return typeof choice === "string" ? choice : choice.label;
894
- });
895
- const values = [...this.selectedIndexes].map((index) => {
896
- const choice = this.filteredChoices[index];
897
- return typeof choice === "string" ? choice : choice.value;
898
- });
923
+ const { values, labels } = this.#selectedChoices();
899
924
  for (const validator of this.#validators) {
900
925
  const validationResult = validator.validate(values);
901
926
  if (isValid(validationResult) === false) {
@@ -923,7 +948,12 @@ var MultiselectPrompt = class extends AbstractPrompt {
923
948
  render();
924
949
  }
925
950
  }
926
- multiselect() {
951
+ async multiselect() {
952
+ if (this.skip) {
953
+ this.destroy();
954
+ const { values } = this.#selectedChoices();
955
+ return values;
956
+ }
927
957
  return new Promise((resolve, reject) => {
928
958
  const answer = this.agent.nextAnswers.shift();
929
959
  if (answer !== void 0) {
package/dist/index.d.cts CHANGED
@@ -49,6 +49,7 @@ interface AbstractPromptOptions {
49
49
  stdin?: Stdin;
50
50
  stdout?: Stdout;
51
51
  message: string;
52
+ skip?: boolean;
52
53
  signal?: AbortSignal;
53
54
  }
54
55
 
package/dist/index.d.ts CHANGED
@@ -49,6 +49,7 @@ interface AbstractPromptOptions {
49
49
  stdin?: Stdin;
50
50
  stdout?: Stdout;
51
51
  message: string;
52
+ skip?: boolean;
52
53
  signal?: AbortSignal;
53
54
  }
54
55
 
package/dist/index.js CHANGED
@@ -1,16 +1,16 @@
1
1
  // src/prompts/question.ts
2
- import { EOL as EOL2 } from "os";
3
- import { styleText as styleText2 } from "util";
2
+ import { EOL as EOL2 } from "node:os";
3
+ import { styleText as styleText2 } from "node:util";
4
4
  import wcwidth from "@topcli/wcwidth";
5
5
 
6
6
  // src/prompts/abstract.ts
7
- import { EOL } from "os";
8
- import { createInterface } from "readline";
9
- import { Writable } from "stream";
10
- import EventEmitter from "events";
7
+ import { EOL } from "node:os";
8
+ import { createInterface } from "node:readline";
9
+ import { Writable } from "node:stream";
10
+ import EventEmitter from "node:events";
11
11
 
12
12
  // src/utils.ts
13
- import process2 from "process";
13
+ import process2 from "node:process";
14
14
  var kAnsiRegex = ansiRegex();
15
15
  function ansiRegex({ onlyFirst = false } = {}) {
16
16
  const pattern = [
@@ -87,6 +87,7 @@ var AbstractPrompt = class _AbstractPrompt extends EventEmitter {
87
87
  stdout;
88
88
  message;
89
89
  signal;
90
+ skip;
90
91
  history;
91
92
  agent;
92
93
  mute;
@@ -101,7 +102,8 @@ var AbstractPrompt = class _AbstractPrompt extends EventEmitter {
101
102
  stdin: input = process.stdin,
102
103
  stdout: output = process.stdout,
103
104
  message,
104
- signal
105
+ signal,
106
+ skip = false
105
107
  } = options;
106
108
  if (typeof message !== "string") {
107
109
  throw new TypeError(`message must be string, ${typeof message} given.`);
@@ -116,6 +118,7 @@ var AbstractPrompt = class _AbstractPrompt extends EventEmitter {
116
118
  this.stdout = output;
117
119
  this.message = message;
118
120
  this.signal = signal;
121
+ this.skip = skip;
119
122
  this.history = [];
120
123
  this.agent = PromptAgent.agent();
121
124
  this.mute = false;
@@ -173,7 +176,7 @@ var AbstractPrompt = class _AbstractPrompt extends EventEmitter {
173
176
  };
174
177
 
175
178
  // src/constants.ts
176
- import { styleText } from "util";
179
+ import { styleText } from "node:util";
177
180
  var kMainSymbols = {
178
181
  tick: "\u2714",
179
182
  cross: "\u2716",
@@ -299,7 +302,11 @@ var QuestionPrompt = class extends AbstractPrompt {
299
302
  this.answerBuffer = void 0;
300
303
  this.#writeAnswer();
301
304
  }
302
- question() {
305
+ async question() {
306
+ if (this.skip) {
307
+ this.destroy();
308
+ return this.defaultValue ?? "";
309
+ }
303
310
  return new Promise(async (resolve, reject) => {
304
311
  this.answer = this.agent.nextAnswers.shift();
305
312
  if (this.answer !== void 0) {
@@ -327,8 +334,8 @@ var QuestionPrompt = class extends AbstractPrompt {
327
334
  };
328
335
 
329
336
  // src/prompts/confirm.ts
330
- import { EOL as EOL3 } from "os";
331
- import { styleText as styleText3 } from "util";
337
+ import { EOL as EOL3 } from "node:os";
338
+ import { styleText as styleText3 } from "node:util";
332
339
  import wcwidth2 from "@topcli/wcwidth";
333
340
  var kToggleKeys = /* @__PURE__ */ new Set([
334
341
  "left",
@@ -376,7 +383,7 @@ var ConfirmPrompt = class extends AbstractPrompt {
376
383
  process.once("exit", this.#boundExitEvent);
377
384
  });
378
385
  }
379
- #onKeypress(resolve, value, key) {
386
+ #onKeypress(resolve, _value, key) {
380
387
  this.stdout.moveCursor(
381
388
  -this.stdout.columns,
382
389
  -Math.floor(wcwidth2(stripAnsi(this.#getQuestionQuery())) / this.stdout.columns)
@@ -418,7 +425,11 @@ var ConfirmPrompt = class extends AbstractPrompt {
418
425
  this.stdout.clearScreenDown();
419
426
  this.write(`${this.selectedValue ? SYMBOLS.Tick : SYMBOLS.Cross} ${styleText3("bold", this.message)}${EOL3}`);
420
427
  }
421
- confirm() {
428
+ async confirm() {
429
+ if (this.skip) {
430
+ this.destroy();
431
+ return this.initial;
432
+ }
422
433
  return new Promise(async (resolve, reject) => {
423
434
  const answer = this.agent.nextAnswers.shift();
424
435
  if (answer !== void 0) {
@@ -447,8 +458,8 @@ var ConfirmPrompt = class extends AbstractPrompt {
447
458
  };
448
459
 
449
460
  // src/prompts/select.ts
450
- import { EOL as EOL4 } from "os";
451
- import { styleText as styleText4 } from "util";
461
+ import { EOL as EOL4 } from "node:os";
462
+ import { styleText as styleText4 } from "node:util";
452
463
  import wcwidth3 from "@topcli/wcwidth";
453
464
  var kRequiredChoiceProperties = ["label", "value"];
454
465
  var SelectPrompt = class extends AbstractPrompt {
@@ -612,7 +623,12 @@ var SelectPrompt = class extends AbstractPrompt {
612
623
  render();
613
624
  }
614
625
  }
615
- select() {
626
+ async select() {
627
+ if (this.skip) {
628
+ this.destroy();
629
+ const answer = this.options.choices[0];
630
+ return typeof answer === "string" ? answer : answer.value;
631
+ }
616
632
  return new Promise((resolve, reject) => {
617
633
  const answer = this.agent.nextAnswers.shift();
618
634
  if (answer !== void 0) {
@@ -682,8 +698,8 @@ var SelectPrompt = class extends AbstractPrompt {
682
698
  };
683
699
 
684
700
  // src/prompts/multiselect.ts
685
- import { EOL as EOL5 } from "os";
686
- import { styleText as styleText5 } from "util";
701
+ import { EOL as EOL5 } from "node:os";
702
+ import { styleText as styleText5 } from "node:util";
687
703
  import wcwidth4 from "@topcli/wcwidth";
688
704
  var kRequiredChoiceProperties2 = ["label", "value"];
689
705
  var MultiselectPrompt = class extends AbstractPrompt {
@@ -732,7 +748,7 @@ var MultiselectPrompt = class extends AbstractPrompt {
732
748
  constructor(options) {
733
749
  const {
734
750
  choices,
735
- preSelectedChoices,
751
+ preSelectedChoices = [],
736
752
  validators = [],
737
753
  showHint = true,
738
754
  ...baseOptions
@@ -756,9 +772,6 @@ var MultiselectPrompt = class extends AbstractPrompt {
756
772
  }
757
773
  }
758
774
  }
759
- if (!preSelectedChoices) {
760
- return;
761
- }
762
775
  for (const choice of preSelectedChoices) {
763
776
  const choiceIndex = this.filteredChoices.findIndex((item) => {
764
777
  if (typeof item === "string") {
@@ -823,6 +836,25 @@ var MultiselectPrompt = class extends AbstractPrompt {
823
836
  const formattedChoice = styleText5("yellow", choices);
824
837
  this.write(`${prefix}${choices ? ` ${formattedChoice}` : ""}${EOL5}`);
825
838
  }
839
+ #selectedChoices() {
840
+ return [...this.selectedIndexes].reduce(
841
+ (acc, index) => {
842
+ const choice = this.filteredChoices[index];
843
+ if (typeof choice === "string") {
844
+ acc.values.push(choice);
845
+ acc.labels.push(choice);
846
+ } else {
847
+ acc.values.push(choice.value);
848
+ acc.labels.push(choice.label);
849
+ }
850
+ return acc;
851
+ },
852
+ {
853
+ values: [],
854
+ labels: []
855
+ }
856
+ );
857
+ }
826
858
  #onProcessExit() {
827
859
  this.stdin.off("keypress", this.#boundKeyPressEvent);
828
860
  this.stdout.moveCursor(-this.stdout.columns, 0);
@@ -847,14 +879,7 @@ var MultiselectPrompt = class extends AbstractPrompt {
847
879
  this.selectedIndexes = new Set([...this.selectedIndexes].filter((index) => index !== this.activeIndex));
848
880
  render();
849
881
  } else if (key.name === "return") {
850
- const labels = [...this.selectedIndexes].map((index) => {
851
- const choice = this.filteredChoices[index];
852
- return typeof choice === "string" ? choice : choice.label;
853
- });
854
- const values = [...this.selectedIndexes].map((index) => {
855
- const choice = this.filteredChoices[index];
856
- return typeof choice === "string" ? choice : choice.value;
857
- });
882
+ const { values, labels } = this.#selectedChoices();
858
883
  for (const validator of this.#validators) {
859
884
  const validationResult = validator.validate(values);
860
885
  if (isValid(validationResult) === false) {
@@ -882,7 +907,12 @@ var MultiselectPrompt = class extends AbstractPrompt {
882
907
  render();
883
908
  }
884
909
  }
885
- multiselect() {
910
+ async multiselect() {
911
+ if (this.skip) {
912
+ this.destroy();
913
+ const { values } = this.#selectedChoices();
914
+ return values;
915
+ }
886
916
  return new Promise((resolve, reject) => {
887
917
  const answer = this.agent.nextAnswers.shift();
888
918
  if (answer !== void 0) {
package/package.json CHANGED
@@ -1,54 +1,54 @@
1
- {
2
- "name": "@topcli/prompts",
3
- "version": "2.0.0",
4
- "description": "Node.js user input library for command-line interfaces.",
5
- "scripts": {
6
- "build": "tsup index.ts --format cjs,esm --dts --clean",
7
- "prepublishOnly": "npm run build",
8
- "test": "glob -c \"tsx --no-warnings=ExperimentalWarning --loader=esmock --test\" \"./test/**/*.test.ts\"",
9
- "coverage": "c8 -r html npm run test",
10
- "lint": "eslint .",
11
- "lint:fix": "eslint . --fix"
12
- },
13
- "main": "./dist/index.js",
14
- "types": "./dist/index.d.ts",
15
- "exports": {
16
- ".": {
17
- "require": "./dist/index.cjs",
18
- "import": "./dist/index.js",
19
- "types": "./dist/index.d.ts"
20
- }
21
- },
22
- "keywords": [
23
- "node.js",
24
- "cli",
25
- "prompt"
26
- ],
27
- "files": [
28
- "dist"
29
- ],
30
- "author": "PierreDemailly <pierredemailly.pro@gmail.com>",
31
- "license": "ISC",
32
- "type": "module",
33
- "devDependencies": {
34
- "@openally/config.eslint": "^1.0.0",
35
- "@openally/config.typescript": "^1.0.3",
36
- "@types/node": "^22.3.0",
37
- "c8": "^10.1.2",
38
- "esmock": "^2.6.7",
39
- "glob": "^11.0.0",
40
- "tsup": "^8.2.4",
41
- "tsx": "^4.17.0",
42
- "typescript": "^5.5.4"
43
- },
44
- "dependencies": {
45
- "@topcli/wcwidth": "^1.0.1"
46
- },
47
- "engines": {
48
- "node": "^20.12.0 || >=21.7.0"
49
- },
50
- "bugs": {
51
- "url": "https://github.com/TopCli/prompts/issues"
52
- },
53
- "homepage": "https://github.com/TopCli/prompts#readme"
54
- }
1
+ {
2
+ "name": "@topcli/prompts",
3
+ "version": "2.1.0",
4
+ "description": "Node.js user input library for command-line interfaces.",
5
+ "scripts": {
6
+ "build": "tsup index.ts --format cjs,esm --dts --clean",
7
+ "prepublishOnly": "npm run build",
8
+ "test": "glob -c \"tsx --no-warnings=ExperimentalWarning --loader=esmock --test\" \"./test/**/*.test.ts\"",
9
+ "coverage": "c8 -r html npm run test",
10
+ "lint": "eslint src test",
11
+ "lint:fix": "eslint . --fix"
12
+ },
13
+ "main": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "require": "./dist/index.cjs",
19
+ "import": "./dist/index.js"
20
+ }
21
+ },
22
+ "keywords": [
23
+ "node.js",
24
+ "cli",
25
+ "prompt"
26
+ ],
27
+ "files": [
28
+ "dist"
29
+ ],
30
+ "author": "PierreDemailly <pierredemailly.pro@gmail.com>",
31
+ "license": "ISC",
32
+ "type": "module",
33
+ "devDependencies": {
34
+ "@openally/config.eslint": "^1.3.0",
35
+ "@openally/config.typescript": "^1.0.3",
36
+ "@types/node": "^22.10.5",
37
+ "c8": "^10.1.3",
38
+ "esmock": "^2.6.9",
39
+ "glob": "^11.0.0",
40
+ "tsup": "^8.3.5",
41
+ "tsx": "^4.19.2",
42
+ "typescript": "^5.7.2"
43
+ },
44
+ "dependencies": {
45
+ "@topcli/wcwidth": "^1.0.1"
46
+ },
47
+ "engines": {
48
+ "node": "^20.12.0 || >=21.7.0"
49
+ },
50
+ "bugs": {
51
+ "url": "https://github.com/TopCli/prompts/issues"
52
+ },
53
+ "homepage": "https://github.com/TopCli/prompts#readme"
54
+ }