npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

multi-prompt

v0.2.0

Published

Run a set of prompts ordered in sections, feeding previous or known answers down through to each section

Downloads

2

Readme

Multi prompt

Divide questions/prompts into multiple sections, where the answers to each section is fed into the next in a chain.

You can furthermore feed multi prompt with a set of known answers, and the user will not be prompted to answer those questions.

Grouping answers by section

You can furthermore group answers into sections to achieve a nested answers structure. This is super useful f.ex to fill out the sections in a nested configuration such as package.json. It also allows you to use namespacing, such that prompts with the same name but in different sections don't conflict as they are merged into their own namespace.

The end result might look like this, built from 4 name prompts grouped in their own section and merged accordingly without overlap or conflict.

{
  name: 'multi-prompt',
  repository: {
    name: 'kmandrup/multi-prompt'
  },
  author: {
    name: 'kristian'
  },
  company: {
    name: 'my-company',
    url: 'my-company.com'
  }
}

No more a need to use repositoryName to distinguish and avoid conflict :)

Simply awesome!

Usage

import * as inquirer from 'inquirer'

import {
  multiPrompt
} from 'multi-prompt'

async function secondPrompt(answers: any, opts: any) {
  return [{
    type: 'input',
    name: 'type',
    default: 'tiger',
    choices: ['bird', 'tiger'],
    message: `At ${answers.age} years old you should be a`
  }]
}

async function firstPrompt(answers: any, opts: any) {
  // first: answers
  return [{
    type: 'input',
    name: 'firstName',
    message: 'First name', // should be humanize of name by default
    when(answers) {
      return answers.length == 0
    }
  }]
}

const prompts = {
  sections: {
    first: {
      // add whatever metadata
      name: 'first',
      label: 'My first section',
      // prompt is required
      prompt: firstPrompt
    },
    second: {
      name: 'second',
      prompt: secondPrompt
    }
  },
  flow: [
    'first',
    'second'
  ]
}

const options = {
  logOn: true, // enable detailed logging
  prompt: inquirer.prompt
  on: {
    sectionNew(section, options) {
      const { name } = section
      // write nice header for section
      chalk.cyan(`:: ${name} ::`)
    },
    sectionAnswers(section, answers, options) {
      const { name } = section
      const answered = Object.keys(answers).join(',')
      options.log(name, answers)

      // sum up what answers have been asked (or provided) when section is done
      chalk.green(`section ${name} received answers for ${answered}`)
    }
  }
}

const knownAnswers = {
  firstName: 'Kristian'
}

const answers = await multiPrompt(prompts, options)

Options

knownAnswers

Object containing a map of answer names and answer provided. Can be used to filter prompts asked to the user

merge

You can pass a custom merge function such as deepmerge to override the default Object.assign (flat merge)

mergeSectionAnswers

Control how answers to each section are merged into the accumulator result. This can f.ex be used to group answers by section instead of having all answers in a flat key/value structure.

You can use the exported function groupSectionAnswers to achieve this.

mergeResultWithKnownAnswers

Control how the resulting answers to all sections are merged with the set of known answers.

on

on is an object that may contain any of the following callback functions

  • sectionNew(section)
  • sectionCreated(section, promptsToAsk)
  • sectionAnswers(section, answers)
  • promptedAnswers(answersPrompted)

defaults

Advanced overrides for full control

  • prompt function to prompt user
  • promptDefToArray(promptDef, options) normalize to array of prompt definitions
  • promptNames(promptDefList, options) names of prompts (ie. keys to be used in answers object)
  • getPromptsToAsk((promptDefList, { include, exclude}, options) filter prompt list by names of known answers or whatever include/exclude is suitable
  • async createPromptsToAsk({section, accAnswers, knownAnswerNames, options, defaults }) create prompts to be asked
  • createLog(options) create logging function

The following is the full set of defaults you can override:

{
  createLog(options),
  log: console.log,
  error(msg, data),
  prompt: inquirer.prompt,
  promptNames(promptDefList, options),
  promptDefToArray(promptDef),
  getPromptsToAsk(promptDefList, { include, exclude} , options),
  async createPromptsToAsk({
    section,
    accAnswers,
    knownAnswerNames,
    options,
    defaults
  }),
  on // see above
}

Prompting options

This library is not limited to be used for text/CLI based prompting but is general purpose. You could integrate prompting using Voice control, use a chatbot API such as Alexa or whatever you like ;)

Fake prompts

In the test suite we use the following fakePrompt function.

function fakePrompt(promptDefList: any, options: any) {
  options.log('fakePrompt', {
    promptDefList
  })
  return promptDefList.reduce((acc: any, promptDef: any) => {
    return Object.assign(acc, {
      [promptDef.name]: promptDef.default || 'unknown'
    })
  }, {})
}

License

MIT