@topcli/prompts 1.10.1 → 2.0.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,4 +1,4 @@
1
- Copyright 2023-2024 Pierre Demailly
1
+ Copyright 2023-2024 TopCli
2
2
 
3
3
  Permission to use, copy, modify, and/or distribute this software for any purpose
4
4
  with or without fee is hereby granted, provided that the above copyright notice
package/README.md CHANGED
@@ -4,7 +4,10 @@
4
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
5
  [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg?style=for-the-badge)](https://github.com/TopCli/prompts/commit-activity)
6
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)
7
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">
8
11
  </div>
9
12
 
10
13
  ## Requirements
@@ -52,18 +55,21 @@ Simple prompt, similar to `rl.question()` with an improved UI.
52
55
 
53
56
  Use `options.secure` if you need to hide both input and answer.
54
57
 
55
- Use `options.validators` to handle user input.
56
-
57
58
  Use `options.signal` to set an `AbortSignal` (throws a [AbortError](#aborterror)).
58
59
 
60
+ Use `options.validators` to handle user input.
61
+
59
62
  **Example**
60
63
 
61
64
  ```js
62
65
  const packageName = await question('Package name', {
63
66
  validators: [
64
67
  {
65
- validate: (value) => !existsSync(join(process.cwd(), value)),
66
- error: (value) => `Folder ${value} already exists`
68
+ validate: (value) => {
69
+ if (!existsSync(join(process.cwd(), value))) {
70
+ return `Folder ${value} already exists`
71
+ }
72
+ }
67
73
  }
68
74
  ]
69
75
  });
@@ -124,7 +130,10 @@ Use `options.signal` to set an `AbortSignal` (throws a [AbortError](#aborterror)
124
130
  confirm(message: string, options?: ConfirmOptions): Promise<boolean>
125
131
  ```
126
132
 
127
- Boolean prompt, return `options.initial` if user input is different from `y`/`yes`/`n`/`no` (case insensitive), (default `false`).
133
+ Boolean prompt, default to `options.initial` (`false`).
134
+
135
+ > [!TIP]
136
+ > You can answer pressing <kbd>Y</kbd> or <kbd>N</kbd>
128
137
 
129
138
  Use `options.signal` to set an `AbortSignal` (throws a [AbortError](#aborterror)).
130
139
 
@@ -221,6 +230,12 @@ export interface ConfirmOptions extends SharedOptions {
221
230
  }
222
231
  ```
223
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
+
224
239
  ## Contributors
225
240
 
226
241
  <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
package/dist/index.cjs CHANGED
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -40,7 +41,7 @@ module.exports = __toCommonJS(prompts_exports);
40
41
 
41
42
  // src/prompts/question.ts
42
43
  var import_node_os2 = require("os");
43
- var import_kleur2 = __toESM(require("kleur"), 1);
44
+ var import_node_util2 = require("util");
44
45
  var import_wcwidth = __toESM(require("@topcli/wcwidth"), 1);
45
46
 
46
47
  // src/prompts/abstract.ts
@@ -54,7 +55,7 @@ var import_node_process = __toESM(require("process"), 1);
54
55
  var kAnsiRegex = ansiRegex();
55
56
  function ansiRegex({ onlyFirst = false } = {}) {
56
57
  const pattern = [
57
- // eslint-disable-next-line max-len
58
+ // eslint-disable-next-line @stylistic/max-len
58
59
  "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
59
60
  "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"
60
61
  ].join("|");
@@ -182,6 +183,9 @@ var AbstractPrompt = class _AbstractPrompt extends import_node_events.default {
182
183
  }
183
184
  this.emit("error", new AbortError("Prompt aborted"));
184
185
  };
186
+ if (this.signal.aborted) {
187
+ this.#signalHandler();
188
+ }
185
189
  this.signal.addEventListener("abort", this.#signalHandler, { once: true });
186
190
  }
187
191
  }
@@ -210,7 +214,7 @@ var AbstractPrompt = class _AbstractPrompt extends import_node_events.default {
210
214
  };
211
215
 
212
216
  // src/constants.ts
213
- var import_kleur = __toESM(require("kleur"), 1);
217
+ var import_node_util = require("util");
214
218
  var kMainSymbols = {
215
219
  tick: "\u2714",
216
220
  cross: "\u2716",
@@ -230,20 +234,45 @@ var kFallbackSymbols = {
230
234
  inactive: "(-)"
231
235
  };
232
236
  var kSymbols = isUnicodeSupported() || process.env.CI ? kMainSymbols : kFallbackSymbols;
233
- var kPointer = import_kleur.default.gray(kSymbols.pointer);
237
+ var kPointer = (0, import_node_util.styleText)("gray", kSymbols.pointer);
234
238
  var SYMBOLS = {
235
- QuestionMark: import_kleur.default.blue().bold("?"),
236
- Tick: import_kleur.default.green().bold(kSymbols.tick),
237
- Cross: import_kleur.default.red().bold(kSymbols.cross),
239
+ QuestionMark: (0, import_node_util.styleText)(["blue", "bold"], "?"),
240
+ Tick: (0, import_node_util.styleText)(["green", "bold"], kSymbols.tick),
241
+ Cross: (0, import_node_util.styleText)(["red", "bold"], kSymbols.cross),
238
242
  Pointer: kPointer,
239
243
  Previous: kSymbols.previous,
240
244
  Next: kSymbols.next,
241
245
  ShowCursor: "\x1B[?25h",
242
246
  HideCursor: "\x1B[?25l",
243
- Active: import_kleur.default.cyan(kSymbols.active),
244
- Inactive: import_kleur.default.gray(kSymbols.inactive)
247
+ Active: (0, import_node_util.styleText)("cyan", kSymbols.active),
248
+ Inactive: (0, import_node_util.styleText)("gray", kSymbols.inactive)
245
249
  };
246
250
 
251
+ // src/validators.ts
252
+ function required() {
253
+ return {
254
+ validate: (input) => {
255
+ const isValid2 = Array.isArray(input) ? input.length > 0 : Boolean(input);
256
+ return isValid2 ? null : { isValid: isValid2, error: "required" };
257
+ }
258
+ };
259
+ }
260
+ function isValid(result) {
261
+ if (typeof result === "object") {
262
+ return result?.isValid !== false;
263
+ }
264
+ if (typeof result === "string") {
265
+ return result.length > 0;
266
+ }
267
+ return true;
268
+ }
269
+ function resultError(result) {
270
+ if (typeof result === "object") {
271
+ return result.error;
272
+ }
273
+ return result;
274
+ }
275
+
247
276
  // src/prompts/question.ts
248
277
  var QuestionPrompt = class extends AbstractPrompt {
249
278
  defaultValue;
@@ -283,16 +312,16 @@ var QuestionPrompt = class extends AbstractPrompt {
283
312
  });
284
313
  }
285
314
  #getQuestionQuery() {
286
- return `${import_kleur2.default.bold(`${SYMBOLS.QuestionMark} ${this.message}${this.tip}`)} ${this.questionSuffixError}`;
315
+ return `${(0, import_node_util2.styleText)("bold", `${SYMBOLS.QuestionMark} ${this.message}${this.tip}`)} ${this.questionSuffixError}`;
287
316
  }
288
317
  #setQuestionSuffixError(error) {
289
- const suffix = import_kleur2.default.red(`[${error}] `);
318
+ const suffix = (0, import_node_util2.styleText)("red", `[${error}] `);
290
319
  this.questionSuffixError = suffix;
291
320
  }
292
321
  #writeAnswer() {
293
322
  const prefix = this.answer ? SYMBOLS.Tick : SYMBOLS.Cross;
294
- const answer = import_kleur2.default.yellow(this.#secure ? "CONFIDENTIAL" : this.answer ?? "");
295
- this.write(`${prefix} ${import_kleur2.default.bold(this.message)} ${SYMBOLS.Pointer} ${answer}${import_node_os2.EOL}`);
323
+ const answer = (0, import_node_util2.styleText)("yellow", this.#secure ? "CONFIDENTIAL" : this.answer ?? "");
324
+ this.write(`${prefix} ${(0, import_node_util2.styleText)("bold", this.message)} ${SYMBOLS.Pointer} ${answer}${import_node_os2.EOL}`);
296
325
  }
297
326
  #onQuestionAnswer() {
298
327
  const questionLineCount = Math.ceil(
@@ -301,9 +330,9 @@ var QuestionPrompt = class extends AbstractPrompt {
301
330
  this.stdout.moveCursor(-this.stdout.columns, -questionLineCount);
302
331
  this.stdout.clearScreenDown();
303
332
  for (const validator of this.#validators) {
304
- if (!validator.validate(this.answer)) {
305
- const error = validator.error(this.answer);
306
- this.#setQuestionSuffixError(error);
333
+ const validationResult = validator.validate(this.answer);
334
+ if (isValid(validationResult) === false) {
335
+ this.#setQuestionSuffixError(resultError(validationResult));
307
336
  this.answerBuffer = this.#question();
308
337
  return;
309
338
  }
@@ -340,7 +369,7 @@ var QuestionPrompt = class extends AbstractPrompt {
340
369
 
341
370
  // src/prompts/confirm.ts
342
371
  var import_node_os3 = require("os");
343
- var import_kleur3 = __toESM(require("kleur"), 1);
372
+ var import_node_util3 = require("util");
344
373
  var import_wcwidth2 = __toESM(require("@topcli/wcwidth"), 1);
345
374
  var kToggleKeys = /* @__PURE__ */ new Set([
346
375
  "left",
@@ -371,8 +400,8 @@ var ConfirmPrompt = class extends AbstractPrompt {
371
400
  this.selectedValue = initial;
372
401
  }
373
402
  #getHint() {
374
- const Yes = import_kleur3.default.bold().underline().cyan("Yes");
375
- const No = import_kleur3.default.bold().underline().cyan("No");
403
+ const Yes = (0, import_node_util3.styleText)(["cyan", "bold", "underline"], "Yes");
404
+ const No = (0, import_node_util3.styleText)(["cyan", "bold", "underline"], "No");
376
405
  return this.selectedValue ? `${Yes}/No` : `Yes/${No}`;
377
406
  }
378
407
  #render() {
@@ -418,7 +447,7 @@ var ConfirmPrompt = class extends AbstractPrompt {
418
447
  this.stdin.off("keypress", this.#boundKeyPressEvent);
419
448
  }
420
449
  #getQuestionQuery() {
421
- const query = import_kleur3.default.bold(`${SYMBOLS.QuestionMark} ${this.message}`);
450
+ const query = (0, import_node_util3.styleText)("bold", `${SYMBOLS.QuestionMark} ${this.message}`);
422
451
  return `${query} ${this.#getHint()}`;
423
452
  }
424
453
  #onQuestionAnswer() {
@@ -428,7 +457,7 @@ var ConfirmPrompt = class extends AbstractPrompt {
428
457
  -Math.floor((0, import_wcwidth2.default)(stripAnsi(this.#getQuestionQuery())) / this.stdout.columns)
429
458
  );
430
459
  this.stdout.clearScreenDown();
431
- this.write(`${this.selectedValue ? SYMBOLS.Tick : SYMBOLS.Cross} ${import_kleur3.default.bold(this.message)}${import_node_os3.EOL}`);
460
+ this.write(`${this.selectedValue ? SYMBOLS.Tick : SYMBOLS.Cross} ${(0, import_node_util3.styleText)("bold", this.message)}${import_node_os3.EOL}`);
432
461
  }
433
462
  confirm() {
434
463
  return new Promise(async (resolve, reject) => {
@@ -460,7 +489,7 @@ var ConfirmPrompt = class extends AbstractPrompt {
460
489
 
461
490
  // src/prompts/select.ts
462
491
  var import_node_os4 = require("os");
463
- var import_kleur4 = __toESM(require("kleur"), 1);
492
+ var import_node_util4 = require("util");
464
493
  var import_wcwidth3 = __toESM(require("@topcli/wcwidth"), 1);
465
494
  var kRequiredChoiceProperties = ["label", "value"];
466
495
  var SelectPrompt = class extends AbstractPrompt {
@@ -567,15 +596,15 @@ var SelectPrompt = class extends AbstractPrompt {
567
596
  this.longestChoice < 10 ? this.longestChoice : 0
568
597
  );
569
598
  const formattedDescription = choice.description ? ` - ${choice.description}` : "";
570
- const color = isChoiceSelected ? import_kleur4.default.white().bold : import_kleur4.default.gray;
571
- const str = `${prefix}${color(`${formattedLabel}${formattedDescription}`)}${import_node_os4.EOL}`;
599
+ const styles = isChoiceSelected ? ["white", "bold"] : ["gray"];
600
+ const str = `${prefix}${(0, import_node_util4.styleText)(styles, `${formattedLabel}${formattedDescription}`)}${import_node_os4.EOL}`;
572
601
  this.write(str);
573
602
  }
574
603
  }
575
604
  #showAnsweredQuestion(choice) {
576
605
  const symbolPrefix = choice === "" ? SYMBOLS.Cross : SYMBOLS.Tick;
577
- const prefix = `${symbolPrefix} ${import_kleur4.default.bold(this.message)} ${SYMBOLS.Pointer}`;
578
- const formattedChoice = import_kleur4.default.yellow(typeof choice === "string" ? choice : choice.label);
606
+ const prefix = `${symbolPrefix} ${(0, import_node_util4.styleText)("bold", this.message)} ${SYMBOLS.Pointer}`;
607
+ const formattedChoice = (0, import_node_util4.styleText)("yellow", typeof choice === "string" ? choice : choice.label);
579
608
  this.write(`${prefix} ${formattedChoice}${import_node_os4.EOL}`);
580
609
  }
581
610
  #onProcessExit() {
@@ -597,9 +626,9 @@ var SelectPrompt = class extends AbstractPrompt {
597
626
  const label = typeof choice === "string" ? choice : choice.label;
598
627
  const value = typeof choice === "string" ? choice : choice.value;
599
628
  for (const validator of this.#validators) {
600
- if (!validator.validate(value)) {
601
- const error = validator.error(value);
602
- render({ error });
629
+ const validationResult = validator.validate(value);
630
+ if (isValid(validationResult) === false) {
631
+ render({ error: resultError(validationResult) });
603
632
  return;
604
633
  }
605
634
  }
@@ -686,16 +715,16 @@ var SelectPrompt = class extends AbstractPrompt {
686
715
  #showQuestion(error = null) {
687
716
  let hint = "";
688
717
  if (error) {
689
- hint = ` ${hint.length > 0 ? " " : ""}${import_kleur4.default.red().bold(`[${error}]`)}`;
718
+ hint = ` ${hint.length > 0 ? " " : ""}${(0, import_node_util4.styleText)(["red", "bold"], `[${error}]`)}`;
690
719
  }
691
- this.questionMessage = `${SYMBOLS.QuestionMark} ${import_kleur4.default.bold(this.message)}${hint}`;
720
+ this.questionMessage = `${SYMBOLS.QuestionMark} ${(0, import_node_util4.styleText)("bold", this.message)}${hint}`;
692
721
  this.write(`${this.questionMessage}${import_node_os4.EOL}`);
693
722
  }
694
723
  };
695
724
 
696
725
  // src/prompts/multiselect.ts
697
726
  var import_node_os5 = require("os");
698
- var import_kleur5 = __toESM(require("kleur"), 1);
727
+ var import_node_util5 = require("util");
699
728
  var import_wcwidth4 = __toESM(require("@topcli/wcwidth"), 1);
700
729
  var kRequiredChoiceProperties2 = ["label", "value"];
701
730
  var MultiselectPrompt = class extends AbstractPrompt {
@@ -824,15 +853,15 @@ var MultiselectPrompt = class extends AbstractPrompt {
824
853
  this.longestChoice < 10 ? this.longestChoice : 0
825
854
  );
826
855
  const formattedDescription = choice.description ? ` - ${choice.description}` : "";
827
- const color = isChoiceActive ? import_kleur5.default.white().bold : import_kleur5.default.gray;
828
- const str = `${prefix} ${color(`${formattedLabel}${formattedDescription}`)}${import_node_os5.EOL}`;
856
+ const styles = isChoiceActive ? ["white", "bold"] : ["gray"];
857
+ const str = `${prefix} ${(0, import_node_util5.styleText)(styles, `${formattedLabel}${formattedDescription}`)}${import_node_os5.EOL}`;
829
858
  this.write(str);
830
859
  }
831
860
  }
832
861
  #showAnsweredQuestion(choices, isAgentAnswer = false) {
833
862
  const prefixSymbol = this.selectedIndexes.size === 0 && !isAgentAnswer ? SYMBOLS.Cross : SYMBOLS.Tick;
834
- const prefix = `${prefixSymbol} ${import_kleur5.default.bold(this.message)} ${SYMBOLS.Pointer}`;
835
- const formattedChoice = import_kleur5.default.yellow(choices);
863
+ const prefix = `${prefixSymbol} ${(0, import_node_util5.styleText)("bold", this.message)} ${SYMBOLS.Pointer}`;
864
+ const formattedChoice = (0, import_node_util5.styleText)("yellow", choices);
836
865
  this.write(`${prefix}${choices ? ` ${formattedChoice}` : ""}${import_node_os5.EOL}`);
837
866
  }
838
867
  #onProcessExit() {
@@ -868,9 +897,9 @@ var MultiselectPrompt = class extends AbstractPrompt {
868
897
  return typeof choice === "string" ? choice : choice.value;
869
898
  });
870
899
  for (const validator of this.#validators) {
871
- if (!validator.validate(values)) {
872
- const error = validator.error(values);
873
- render({ error });
900
+ const validationResult = validator.validate(values);
901
+ if (isValid(validationResult) === false) {
902
+ render({ error: resultError(validationResult) });
874
903
  return;
875
904
  }
876
905
  }
@@ -955,26 +984,19 @@ var MultiselectPrompt = class extends AbstractPrompt {
955
984
  });
956
985
  }
957
986
  #showQuestion(error = null) {
958
- let hint = this.#showHint ? import_kleur5.default.gray(
959
- // eslint-disable-next-line max-len
960
- `(Press ${import_kleur5.default.bold("<Ctrl+A>")} to toggle all, ${import_kleur5.default.bold("<Left/Right>")} to toggle, ${import_kleur5.default.bold("<Return>")} to submit)`
987
+ let hint = this.#showHint ? (0, import_node_util5.styleText)(
988
+ "gray",
989
+ // eslint-disable-next-line @stylistic/max-len
990
+ `(Press ${(0, import_node_util5.styleText)("bold", "<Ctrl+A>")} to toggle all, ${(0, import_node_util5.styleText)("bold", "<Left/Right>")} to toggle, ${(0, import_node_util5.styleText)("bold", "<Return>")} to submit)`
961
991
  ) : "";
962
992
  if (error) {
963
- hint += `${hint.length > 0 ? " " : ""}${import_kleur5.default.red().bold(`[${error}]`)}`;
993
+ hint += `${hint.length > 0 ? " " : ""}${(0, import_node_util5.styleText)(["red", "bold"], `[${error}]`)}`;
964
994
  }
965
- this.questionMessage = `${SYMBOLS.QuestionMark} ${import_kleur5.default.bold(this.message)}${hint.length > 0 ? ` ${hint}` : ""}`;
995
+ this.questionMessage = `${SYMBOLS.QuestionMark} ${(0, import_node_util5.styleText)("bold", this.message)}${hint.length > 0 ? ` ${hint}` : ""}`;
966
996
  this.write(`${this.questionMessage}${import_node_os5.EOL}`);
967
997
  }
968
998
  };
969
999
 
970
- // src/validators.ts
971
- function required() {
972
- return {
973
- validate: (input) => Array.isArray(input) ? input.length > 0 : Boolean(input),
974
- error: () => "required"
975
- };
976
- }
977
-
978
1000
  // index.ts
979
1001
  async function question(message, options = {}) {
980
1002
  return new QuestionPrompt({ ...options, message }).question();
@@ -983,7 +1005,7 @@ async function select(message, options) {
983
1005
  const selectPrompt = new SelectPrompt({ ...options, message });
984
1006
  return selectPrompt.select();
985
1007
  }
986
- async function confirm(message, options) {
1008
+ async function confirm(message, options = {}) {
987
1009
  const confirmPrompt = new ConfirmPrompt({ ...options, message });
988
1010
  return confirmPrompt.confirm();
989
1011
  }
package/dist/index.d.cts CHANGED
@@ -1,6 +1,15 @@
1
+ type ValidResponseObject = {
2
+ isValid?: true;
3
+ };
4
+ type InvalidResponseObject = {
5
+ isValid: false;
6
+ error: string;
7
+ };
8
+ type ValidationResponse = InvalidResponse | ValidResponse;
9
+ type InvalidResponse = string | InvalidResponseObject;
10
+ type ValidResponse = null | undefined | true | ValidResponseObject;
1
11
  interface PromptValidator<T = string | string[] | boolean> {
2
- validate: (input: T) => boolean;
3
- error: (input: T) => string;
12
+ validate: (input: T) => ValidationResponse;
4
13
  }
5
14
  declare function required<T = string | string[] | boolean>(): PromptValidator<T>;
6
15
 
@@ -80,7 +89,7 @@ interface SelectOptions extends AbstractPromptOptions {
80
89
 
81
90
  declare function question(message: string, options?: Omit<QuestionOptions, "message">): Promise<string>;
82
91
  declare function select(message: string, options: Omit<SelectOptions, "message">): Promise<string>;
83
- declare function confirm(message: string, options: Omit<ConfirmOptions, "message">): Promise<boolean>;
92
+ declare function confirm(message: string, options?: Omit<ConfirmOptions, "message">): Promise<boolean>;
84
93
  declare function multiselect(message: string, options: Omit<MultiselectOptions, "message">): Promise<string[]>;
85
94
 
86
95
  export { type AbstractPromptOptions, type Choice, type ConfirmOptions, type MultiselectOptions, PromptAgent, type PromptValidator, type QuestionOptions, type SelectOptions, confirm, multiselect, question, required, select };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,15 @@
1
+ type ValidResponseObject = {
2
+ isValid?: true;
3
+ };
4
+ type InvalidResponseObject = {
5
+ isValid: false;
6
+ error: string;
7
+ };
8
+ type ValidationResponse = InvalidResponse | ValidResponse;
9
+ type InvalidResponse = string | InvalidResponseObject;
10
+ type ValidResponse = null | undefined | true | ValidResponseObject;
1
11
  interface PromptValidator<T = string | string[] | boolean> {
2
- validate: (input: T) => boolean;
3
- error: (input: T) => string;
12
+ validate: (input: T) => ValidationResponse;
4
13
  }
5
14
  declare function required<T = string | string[] | boolean>(): PromptValidator<T>;
6
15
 
@@ -80,7 +89,7 @@ interface SelectOptions extends AbstractPromptOptions {
80
89
 
81
90
  declare function question(message: string, options?: Omit<QuestionOptions, "message">): Promise<string>;
82
91
  declare function select(message: string, options: Omit<SelectOptions, "message">): Promise<string>;
83
- declare function confirm(message: string, options: Omit<ConfirmOptions, "message">): Promise<boolean>;
92
+ declare function confirm(message: string, options?: Omit<ConfirmOptions, "message">): Promise<boolean>;
84
93
  declare function multiselect(message: string, options: Omit<MultiselectOptions, "message">): Promise<string[]>;
85
94
 
86
95
  export { type AbstractPromptOptions, type Choice, type ConfirmOptions, type MultiselectOptions, PromptAgent, type PromptValidator, type QuestionOptions, type SelectOptions, confirm, multiselect, question, required, select };
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/prompts/question.ts
2
2
  import { EOL as EOL2 } from "os";
3
- import kleur2 from "kleur";
3
+ import { styleText as styleText2 } from "util";
4
4
  import wcwidth from "@topcli/wcwidth";
5
5
 
6
6
  // src/prompts/abstract.ts
@@ -14,7 +14,7 @@ import process2 from "process";
14
14
  var kAnsiRegex = ansiRegex();
15
15
  function ansiRegex({ onlyFirst = false } = {}) {
16
16
  const pattern = [
17
- // eslint-disable-next-line max-len
17
+ // eslint-disable-next-line @stylistic/max-len
18
18
  "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
19
19
  "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"
20
20
  ].join("|");
@@ -142,6 +142,9 @@ var AbstractPrompt = class _AbstractPrompt extends EventEmitter {
142
142
  }
143
143
  this.emit("error", new AbortError("Prompt aborted"));
144
144
  };
145
+ if (this.signal.aborted) {
146
+ this.#signalHandler();
147
+ }
145
148
  this.signal.addEventListener("abort", this.#signalHandler, { once: true });
146
149
  }
147
150
  }
@@ -170,7 +173,7 @@ var AbstractPrompt = class _AbstractPrompt extends EventEmitter {
170
173
  };
171
174
 
172
175
  // src/constants.ts
173
- import kleur from "kleur";
176
+ import { styleText } from "util";
174
177
  var kMainSymbols = {
175
178
  tick: "\u2714",
176
179
  cross: "\u2716",
@@ -190,20 +193,45 @@ var kFallbackSymbols = {
190
193
  inactive: "(-)"
191
194
  };
192
195
  var kSymbols = isUnicodeSupported() || process.env.CI ? kMainSymbols : kFallbackSymbols;
193
- var kPointer = kleur.gray(kSymbols.pointer);
196
+ var kPointer = styleText("gray", kSymbols.pointer);
194
197
  var SYMBOLS = {
195
- QuestionMark: kleur.blue().bold("?"),
196
- Tick: kleur.green().bold(kSymbols.tick),
197
- Cross: kleur.red().bold(kSymbols.cross),
198
+ QuestionMark: styleText(["blue", "bold"], "?"),
199
+ Tick: styleText(["green", "bold"], kSymbols.tick),
200
+ Cross: styleText(["red", "bold"], kSymbols.cross),
198
201
  Pointer: kPointer,
199
202
  Previous: kSymbols.previous,
200
203
  Next: kSymbols.next,
201
204
  ShowCursor: "\x1B[?25h",
202
205
  HideCursor: "\x1B[?25l",
203
- Active: kleur.cyan(kSymbols.active),
204
- Inactive: kleur.gray(kSymbols.inactive)
206
+ Active: styleText("cyan", kSymbols.active),
207
+ Inactive: styleText("gray", kSymbols.inactive)
205
208
  };
206
209
 
210
+ // src/validators.ts
211
+ function required() {
212
+ return {
213
+ validate: (input) => {
214
+ const isValid2 = Array.isArray(input) ? input.length > 0 : Boolean(input);
215
+ return isValid2 ? null : { isValid: isValid2, error: "required" };
216
+ }
217
+ };
218
+ }
219
+ function isValid(result) {
220
+ if (typeof result === "object") {
221
+ return result?.isValid !== false;
222
+ }
223
+ if (typeof result === "string") {
224
+ return result.length > 0;
225
+ }
226
+ return true;
227
+ }
228
+ function resultError(result) {
229
+ if (typeof result === "object") {
230
+ return result.error;
231
+ }
232
+ return result;
233
+ }
234
+
207
235
  // src/prompts/question.ts
208
236
  var QuestionPrompt = class extends AbstractPrompt {
209
237
  defaultValue;
@@ -243,16 +271,16 @@ var QuestionPrompt = class extends AbstractPrompt {
243
271
  });
244
272
  }
245
273
  #getQuestionQuery() {
246
- return `${kleur2.bold(`${SYMBOLS.QuestionMark} ${this.message}${this.tip}`)} ${this.questionSuffixError}`;
274
+ return `${styleText2("bold", `${SYMBOLS.QuestionMark} ${this.message}${this.tip}`)} ${this.questionSuffixError}`;
247
275
  }
248
276
  #setQuestionSuffixError(error) {
249
- const suffix = kleur2.red(`[${error}] `);
277
+ const suffix = styleText2("red", `[${error}] `);
250
278
  this.questionSuffixError = suffix;
251
279
  }
252
280
  #writeAnswer() {
253
281
  const prefix = this.answer ? SYMBOLS.Tick : SYMBOLS.Cross;
254
- const answer = kleur2.yellow(this.#secure ? "CONFIDENTIAL" : this.answer ?? "");
255
- this.write(`${prefix} ${kleur2.bold(this.message)} ${SYMBOLS.Pointer} ${answer}${EOL2}`);
282
+ const answer = styleText2("yellow", this.#secure ? "CONFIDENTIAL" : this.answer ?? "");
283
+ this.write(`${prefix} ${styleText2("bold", this.message)} ${SYMBOLS.Pointer} ${answer}${EOL2}`);
256
284
  }
257
285
  #onQuestionAnswer() {
258
286
  const questionLineCount = Math.ceil(
@@ -261,9 +289,9 @@ var QuestionPrompt = class extends AbstractPrompt {
261
289
  this.stdout.moveCursor(-this.stdout.columns, -questionLineCount);
262
290
  this.stdout.clearScreenDown();
263
291
  for (const validator of this.#validators) {
264
- if (!validator.validate(this.answer)) {
265
- const error = validator.error(this.answer);
266
- this.#setQuestionSuffixError(error);
292
+ const validationResult = validator.validate(this.answer);
293
+ if (isValid(validationResult) === false) {
294
+ this.#setQuestionSuffixError(resultError(validationResult));
267
295
  this.answerBuffer = this.#question();
268
296
  return;
269
297
  }
@@ -300,7 +328,7 @@ var QuestionPrompt = class extends AbstractPrompt {
300
328
 
301
329
  // src/prompts/confirm.ts
302
330
  import { EOL as EOL3 } from "os";
303
- import kleur3 from "kleur";
331
+ import { styleText as styleText3 } from "util";
304
332
  import wcwidth2 from "@topcli/wcwidth";
305
333
  var kToggleKeys = /* @__PURE__ */ new Set([
306
334
  "left",
@@ -331,8 +359,8 @@ var ConfirmPrompt = class extends AbstractPrompt {
331
359
  this.selectedValue = initial;
332
360
  }
333
361
  #getHint() {
334
- const Yes = kleur3.bold().underline().cyan("Yes");
335
- const No = kleur3.bold().underline().cyan("No");
362
+ const Yes = styleText3(["cyan", "bold", "underline"], "Yes");
363
+ const No = styleText3(["cyan", "bold", "underline"], "No");
336
364
  return this.selectedValue ? `${Yes}/No` : `Yes/${No}`;
337
365
  }
338
366
  #render() {
@@ -378,7 +406,7 @@ var ConfirmPrompt = class extends AbstractPrompt {
378
406
  this.stdin.off("keypress", this.#boundKeyPressEvent);
379
407
  }
380
408
  #getQuestionQuery() {
381
- const query = kleur3.bold(`${SYMBOLS.QuestionMark} ${this.message}`);
409
+ const query = styleText3("bold", `${SYMBOLS.QuestionMark} ${this.message}`);
382
410
  return `${query} ${this.#getHint()}`;
383
411
  }
384
412
  #onQuestionAnswer() {
@@ -388,7 +416,7 @@ var ConfirmPrompt = class extends AbstractPrompt {
388
416
  -Math.floor(wcwidth2(stripAnsi(this.#getQuestionQuery())) / this.stdout.columns)
389
417
  );
390
418
  this.stdout.clearScreenDown();
391
- this.write(`${this.selectedValue ? SYMBOLS.Tick : SYMBOLS.Cross} ${kleur3.bold(this.message)}${EOL3}`);
419
+ this.write(`${this.selectedValue ? SYMBOLS.Tick : SYMBOLS.Cross} ${styleText3("bold", this.message)}${EOL3}`);
392
420
  }
393
421
  confirm() {
394
422
  return new Promise(async (resolve, reject) => {
@@ -420,7 +448,7 @@ var ConfirmPrompt = class extends AbstractPrompt {
420
448
 
421
449
  // src/prompts/select.ts
422
450
  import { EOL as EOL4 } from "os";
423
- import kleur4 from "kleur";
451
+ import { styleText as styleText4 } from "util";
424
452
  import wcwidth3 from "@topcli/wcwidth";
425
453
  var kRequiredChoiceProperties = ["label", "value"];
426
454
  var SelectPrompt = class extends AbstractPrompt {
@@ -527,15 +555,15 @@ var SelectPrompt = class extends AbstractPrompt {
527
555
  this.longestChoice < 10 ? this.longestChoice : 0
528
556
  );
529
557
  const formattedDescription = choice.description ? ` - ${choice.description}` : "";
530
- const color = isChoiceSelected ? kleur4.white().bold : kleur4.gray;
531
- const str = `${prefix}${color(`${formattedLabel}${formattedDescription}`)}${EOL4}`;
558
+ const styles = isChoiceSelected ? ["white", "bold"] : ["gray"];
559
+ const str = `${prefix}${styleText4(styles, `${formattedLabel}${formattedDescription}`)}${EOL4}`;
532
560
  this.write(str);
533
561
  }
534
562
  }
535
563
  #showAnsweredQuestion(choice) {
536
564
  const symbolPrefix = choice === "" ? SYMBOLS.Cross : SYMBOLS.Tick;
537
- const prefix = `${symbolPrefix} ${kleur4.bold(this.message)} ${SYMBOLS.Pointer}`;
538
- const formattedChoice = kleur4.yellow(typeof choice === "string" ? choice : choice.label);
565
+ const prefix = `${symbolPrefix} ${styleText4("bold", this.message)} ${SYMBOLS.Pointer}`;
566
+ const formattedChoice = styleText4("yellow", typeof choice === "string" ? choice : choice.label);
539
567
  this.write(`${prefix} ${formattedChoice}${EOL4}`);
540
568
  }
541
569
  #onProcessExit() {
@@ -557,9 +585,9 @@ var SelectPrompt = class extends AbstractPrompt {
557
585
  const label = typeof choice === "string" ? choice : choice.label;
558
586
  const value = typeof choice === "string" ? choice : choice.value;
559
587
  for (const validator of this.#validators) {
560
- if (!validator.validate(value)) {
561
- const error = validator.error(value);
562
- render({ error });
588
+ const validationResult = validator.validate(value);
589
+ if (isValid(validationResult) === false) {
590
+ render({ error: resultError(validationResult) });
563
591
  return;
564
592
  }
565
593
  }
@@ -646,16 +674,16 @@ var SelectPrompt = class extends AbstractPrompt {
646
674
  #showQuestion(error = null) {
647
675
  let hint = "";
648
676
  if (error) {
649
- hint = ` ${hint.length > 0 ? " " : ""}${kleur4.red().bold(`[${error}]`)}`;
677
+ hint = ` ${hint.length > 0 ? " " : ""}${styleText4(["red", "bold"], `[${error}]`)}`;
650
678
  }
651
- this.questionMessage = `${SYMBOLS.QuestionMark} ${kleur4.bold(this.message)}${hint}`;
679
+ this.questionMessage = `${SYMBOLS.QuestionMark} ${styleText4("bold", this.message)}${hint}`;
652
680
  this.write(`${this.questionMessage}${EOL4}`);
653
681
  }
654
682
  };
655
683
 
656
684
  // src/prompts/multiselect.ts
657
685
  import { EOL as EOL5 } from "os";
658
- import kleur5 from "kleur";
686
+ import { styleText as styleText5 } from "util";
659
687
  import wcwidth4 from "@topcli/wcwidth";
660
688
  var kRequiredChoiceProperties2 = ["label", "value"];
661
689
  var MultiselectPrompt = class extends AbstractPrompt {
@@ -784,15 +812,15 @@ var MultiselectPrompt = class extends AbstractPrompt {
784
812
  this.longestChoice < 10 ? this.longestChoice : 0
785
813
  );
786
814
  const formattedDescription = choice.description ? ` - ${choice.description}` : "";
787
- const color = isChoiceActive ? kleur5.white().bold : kleur5.gray;
788
- const str = `${prefix} ${color(`${formattedLabel}${formattedDescription}`)}${EOL5}`;
815
+ const styles = isChoiceActive ? ["white", "bold"] : ["gray"];
816
+ const str = `${prefix} ${styleText5(styles, `${formattedLabel}${formattedDescription}`)}${EOL5}`;
789
817
  this.write(str);
790
818
  }
791
819
  }
792
820
  #showAnsweredQuestion(choices, isAgentAnswer = false) {
793
821
  const prefixSymbol = this.selectedIndexes.size === 0 && !isAgentAnswer ? SYMBOLS.Cross : SYMBOLS.Tick;
794
- const prefix = `${prefixSymbol} ${kleur5.bold(this.message)} ${SYMBOLS.Pointer}`;
795
- const formattedChoice = kleur5.yellow(choices);
822
+ const prefix = `${prefixSymbol} ${styleText5("bold", this.message)} ${SYMBOLS.Pointer}`;
823
+ const formattedChoice = styleText5("yellow", choices);
796
824
  this.write(`${prefix}${choices ? ` ${formattedChoice}` : ""}${EOL5}`);
797
825
  }
798
826
  #onProcessExit() {
@@ -828,9 +856,9 @@ var MultiselectPrompt = class extends AbstractPrompt {
828
856
  return typeof choice === "string" ? choice : choice.value;
829
857
  });
830
858
  for (const validator of this.#validators) {
831
- if (!validator.validate(values)) {
832
- const error = validator.error(values);
833
- render({ error });
859
+ const validationResult = validator.validate(values);
860
+ if (isValid(validationResult) === false) {
861
+ render({ error: resultError(validationResult) });
834
862
  return;
835
863
  }
836
864
  }
@@ -915,26 +943,19 @@ var MultiselectPrompt = class extends AbstractPrompt {
915
943
  });
916
944
  }
917
945
  #showQuestion(error = null) {
918
- let hint = this.#showHint ? kleur5.gray(
919
- // eslint-disable-next-line max-len
920
- `(Press ${kleur5.bold("<Ctrl+A>")} to toggle all, ${kleur5.bold("<Left/Right>")} to toggle, ${kleur5.bold("<Return>")} to submit)`
946
+ let hint = this.#showHint ? styleText5(
947
+ "gray",
948
+ // eslint-disable-next-line @stylistic/max-len
949
+ `(Press ${styleText5("bold", "<Ctrl+A>")} to toggle all, ${styleText5("bold", "<Left/Right>")} to toggle, ${styleText5("bold", "<Return>")} to submit)`
921
950
  ) : "";
922
951
  if (error) {
923
- hint += `${hint.length > 0 ? " " : ""}${kleur5.red().bold(`[${error}]`)}`;
952
+ hint += `${hint.length > 0 ? " " : ""}${styleText5(["red", "bold"], `[${error}]`)}`;
924
953
  }
925
- this.questionMessage = `${SYMBOLS.QuestionMark} ${kleur5.bold(this.message)}${hint.length > 0 ? ` ${hint}` : ""}`;
954
+ this.questionMessage = `${SYMBOLS.QuestionMark} ${styleText5("bold", this.message)}${hint.length > 0 ? ` ${hint}` : ""}`;
926
955
  this.write(`${this.questionMessage}${EOL5}`);
927
956
  }
928
957
  };
929
958
 
930
- // src/validators.ts
931
- function required() {
932
- return {
933
- validate: (input) => Array.isArray(input) ? input.length > 0 : Boolean(input),
934
- error: () => "required"
935
- };
936
- }
937
-
938
959
  // index.ts
939
960
  async function question(message, options = {}) {
940
961
  return new QuestionPrompt({ ...options, message }).question();
@@ -943,7 +964,7 @@ async function select(message, options) {
943
964
  const selectPrompt = new SelectPrompt({ ...options, message });
944
965
  return selectPrompt.select();
945
966
  }
946
- async function confirm(message, options) {
967
+ async function confirm(message, options = {}) {
947
968
  const confirmPrompt = new ConfirmPrompt({ ...options, message });
948
969
  return confirmPrompt.confirm();
949
970
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topcli/prompts",
3
- "version": "1.10.1",
3
+ "version": "2.0.0",
4
4
  "description": "Node.js user input library for command-line interfaces.",
5
5
  "scripts": {
6
6
  "build": "tsup index.ts --format cjs,esm --dts --clean",
@@ -31,22 +31,21 @@
31
31
  "license": "ISC",
32
32
  "type": "module",
33
33
  "devDependencies": {
34
- "@nodesecure/eslint-config": "^1.9.0",
35
- "@types/node": "^20.11.6",
36
- "c8": "^9.1.0",
37
- "eslint": "^9.2.0",
38
- "esmock": "^2.6.3",
39
- "glob": "^10.3.10",
40
- "tsup": "^8.0.1",
41
- "tsx": "^4.7.0",
42
- "typescript": "^5.3.3"
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
43
  },
44
44
  "dependencies": {
45
- "@topcli/wcwidth": "^1.0.1",
46
- "kleur": "^4.1.5"
45
+ "@topcli/wcwidth": "^1.0.1"
47
46
  },
48
47
  "engines": {
49
- "node": ">=14"
48
+ "node": "^20.12.0 || >=21.7.0"
50
49
  },
51
50
  "bugs": {
52
51
  "url": "https://github.com/TopCli/prompts/issues"