terkelg / prompts

❯ Lightweight, beautiful and user-friendly interactive prompts
MIT License
8.83k stars 304 forks source link

Export small single-question prompts #288

Open franciscop opened 3 years ago

franciscop commented 3 years ago

Is your feature request related to a problem?

It becomes a bit cumbersome to write all the object definitions all the time.

Describe the solution you'd like

Export a lightweight way of handling single questions:

// Before
import prompts from 'prompts';

const response = await prompts({
  type: ' text',
  name: 'twitter',
  message: 'What is your twitter handle?'
});
const twitter = response.twitter;

// After
import { text } from 'prompts';

const twitter = await text('What is your twitter handle?');

Describe alternatives you've considered

Publishing a minimal library wrapper myself. This feature request might not be a good fit for the current prompts API, so if this feature request is not good I can publish a wrapper. Prompts already works amazingly well so I prefer a wrapper than maintaining a fork.

Additional context

While I think the small example above is already clear, it becomes even better the more questions you have:

// Style A (with this proposal)
import { text, confirm } from "prompts";

const twitter = await text("What's your twitter handle?");
const tos = await confirm("Accept our Terms of Service?", { initial: true });

console.log({ twitter, tos });
// { twitter: "@fpresencia", tos: true }
// Style B (also with this proposal)
import { text, confirm } from "prompts";

const response = {
  twitter: await text("What's your twitter handle?"),
  tos: await confirm("Accept our Terms of Service?", { initial: true }),
};

console.log(response);
// { twitter: "@fpresencia", tos: true }

VS

// Current prompts implementation for the same above
import prompts from "prompts";

const response = await prompts([
  {
    type: "text",
    name: "twitter",
    message: "What's your twitter handle?"
  },
  {
    type: "confirm",
    name: "tos",
    message: "Accept our Terms of Service?",
    initial: true
  }
});

console.log(response);
// { twitter: "@fpresencia", tos: true }
franciscop commented 3 years ago

I have actually implemented this already as a wrapper, but wanted to ask in the repo if this could be wanted internally (would need to convert it to commonjs). This is the whole wrapper code that makes this feature request work:

import prompts from "prompts";

Object.keys(prompts.prompts).forEach((type) => {
  prompts[type] = async (message, opts) => {
    const response = await prompts({ ...opts, name: "value", type, message });
    return response.value;
  };
});

export const text = prompts.text;
export const password = prompts.password;
export const invisible = prompts.invisible;
export const number = prompts.number;
export const confirm = prompts.confirm;
export const list = prompts.list;
export const toggle = prompts.toggle;
export const select = prompts.select;
export const multiselect = prompts.multiselect;
export const autocompleteMultiselect = prompts.autocompleteMultiselect;
export const autocomplete = prompts.autocomplete;
export const date = prompts.date;

export default prompts;
terkelg commented 3 years ago

I think this is a good feature @franciscop. I like the API – can you do a PR and document it?

franciscop commented 3 years ago

Awesome! With commonjs (which I assume Prompts still wants) things get trickier but I believe it's possible to have both named exports destructuring like this:

import { text, confirm } from 'prompts';
// OR
const { text, confirm } = require('prompts');

const twitter = await text("What's your twitter handle?");
const tos = await confirm("Accept our Terms of Service?", { initial: true });

console.log({ twitter, tos });
// { twitter: "@fpresencia", tos: true }

Let me try a couple of things and come back at you :smile: