Inquirer.js

repository·main·Indexed 12 days ago

https://github.com/sboudrias/inquirer.js

A collection of lightweight, performant, and easy-to-use interactive command-line user interface prompts for Node.js applications. It includes a variety of prompt types such as checkbox, confirm, and editor, as well as a core library (@inquirer/core) for building custom prompts using a hook-based rendering paradigm (useState, useKeypress, useEffect, useMemo) and a theming system for visual customization.

Tokens
38.4K
Snippets
134
Records
185
Agent score
96%

What's inside Inquirer.js

  1. Overview of Inquirer.js

    main

    Inquirer.js is a collection of common interactive command line user interfaces for Node.js. It is designed to ease the process of:

    • Providing error feedback
    • Asking questions
    • Parsing input
    • Validating answers
    • Managing hierarchical prompts

    Note: Inquirer.js provides the user interface and the inquiry session flow. It is not a full-blown command line program utility (for those needs, consider commander, vorpal, or args).

  2. Available Prompt Types

    main

    The @inquirer/prompts package provides several interactive prompt types. Each has its own specific configuration options and behavior:

    • input: Standard text input.
    • select: A list of options where the user selects one.
    • checkbox: A list of options where the user can select multiple items.
    • confirm: A boolean (yes/no) confirmation prompt.
    • search: An input prompt with search/filtering capabilities.
    • password: A text input that masks characters.
    • expand: A prompt that offers multiple choices via single-character keys.
    • editor: Launches the user's preferred editor (via $VISUAL or $EDITOR) to edit content in a temporary file.
    • number: Similar to input but includes built-in number validation.
    • rawlist: A list prompt (specific implementation details available in its own documentation).
  3. Explore community Inquirer prompts

    main

    Beyond the core packages, there is a variety of community-maintained prompts for specialized UI needs:

    • Interactive List Prompt: Select via arrow keys or associated keypresses.
    • Action Select Prompt: Choose an item and an action (e.g., Open, Edit, Delete) via keypress.
    • Table Multiple Prompt: Select multiple items from a grid/table display.
    • Toggle Prompt: A simple toggle switch for boolean values.
    • Sortable Checkbox Prompt: Checkbox list that allows reordering items with ctrl+up/down.
    • Multi Select Prompt: Select and filter multiple options.
    • File Selector Prompt: A navigable file/directory tree explorer.
    • Select Prompt with Stateful Banner: A select prompt that displays a dynamic banner above it.
    • Ordered Checkbox Prompt: A checkbox list that maintains the order of selection.
    • Checkbox Plus Plus Prompt: Modern multiselect with search, filtering, and autocomplete.
    • Tree Prompt: Navigate and expand/collapse hierarchical tree structures.
  4. How validation and autocomplete interact

    main

    Validation in the search prompt drives the autocomplete behavior:

    1. If a user submits a value that fails validate, the prompt compares the value to the current search term.
    2. If they are identical, the error message is displayed.
    3. If they are different, the prompt autocompletes the search term to match the selected value and triggers a new search.
    4. Pressing tab also triggers term autocomplete.

    This pattern allows for progressive autocomplete searches where users can narrow down results by selecting items.

  5. How createPrompt() works

    main

    The createPrompt() function is the entry point for building prompts. It accepts a rendering function that runs every time the prompt state changes. The rendering function must return either a single string or a tuple of two strings [prompt, content].

    • The first string (or the only string) is the prompt line where the cursor appears.
    • The second string (if provided in a tuple) is content rendered under the prompt, such as error messages.

    To finish the prompt and return a value to the caller, you must invoke the done(answer) callback.

    import { createPrompt } from '@inquirer/core';
    
    const input = createPrompt((config, done) => {
      // Logic goes here
      return '? My question';
    });
    
    const answer = await input({/* config */});
  6. Configure a Question object

    main

    A question object is a hash containing configuration for a specific prompt. Key properties include:

    • type (String): The prompt type. Defaults to input. Possible values: input, number, confirm, list, rawlist, expand, checkbox, password, editor.
    • name (String): The key used to store the answer in the results object. Periods in the name define a path in the answers hash.
    • message (String|Function): The question text. If a function, the first parameter is the current answers hash.
    • default (String|Number|Boolean|Array|Function): The default value. If a function, the first parameter is the current answers hash.
    • choices (Array|Function): An array of choices or a function returning them. Array values can be simple types or objects with { name, value, short }.
    • validate (Function): Validates input. Returns true if valid, or a String error message if invalid.
    • filter (Function): Transforms the input before it is added to the answers hash.
    • transformer (Function): Transforms the input for display purposes only (does not affect the stored answer).
    • when (Function|Boolean): Determines if the question should be asked based on previous answers.
    • pageSize (Number): Limits the number of lines rendered for list-based prompts.
    • prefix / suffix (String): Customizes the prompt decoration.
    • askAnswered (Boolean): If true, forces the prompt even if the answer is already in the answers object.
    • loop (Boolean): Enables list looping. Defaults to true.
    • waitUserInput (Boolean): Whether to wait for input before opening the system editor. Defaults to true.

    Note on Asynchronicity: default, choices, validate, filter, and when can be asynchronous. You can return a Promise or use the legacy this.async() method.

    {
      /* Preferred way: with promise */
      filter() {
        return new Promise(/* etc... */);
      },
    
      /* Legacy way: with this.async */
      validate: function (input) {
        // Declare function as asynchronous, and save the done callback
        const done = this.async();
    
        // Do async stuff
        setTimeout(function() {
          if (typeof input !== 'number') {
            // Pass the return value in the done callback
            done('You need to provide a number');
          } else {
            done(null, true);
          }
        }, 3000);
      }
    }
  7. Understand the synchronous design and async alternatives

    main

    The core design of @inquirer/external-editor is synchronous. This ensures the editor has complete control over stdin and stdout, preventing conflicts with other packages (like readline) that might attempt to use the same streams in an interactive CLI environment.

    If you must use asynchronous patterns, use editAsync() or runAsync(). Warning: If you use async methods while other listeners are active on stdin, stdout, or stderr, you may encounter issues. Ensure you remove any other listeners on these streams before proceeding.

  8. How workspace discovery works

    main

    The CLI automatically discovers workspaces using:

    • The workspaces field in package.json.
    • pnpm-workspace.yaml files.

    Behavioral Notes:

    • If no workspaces are configured, the root package.json is treated as a single-package project.
    • Private packages are ignored by default.
  9. Configure global or per-prompt keybindings

    main

    You can enable alternative navigation keybindings (Vim or Emacs) in two ways:

    1. Globally: Set the INQUIRER_KEYBINDINGS environment variable to vim, emacs, or vim,emacs.
    2. Per-prompt: Override the environment setting by passing keybindings in the theme object of the prompt configuration.
  10. Use the Reactive interface with RxJS

    main

    Inquirer supports dynamic question flows by accepting an RxJS-compatible Observable. You can push new questions into the stream over time.

    const prompts = new Rx.Subject();
    inquirer.prompt(prompts);
    
    // At some point in the future, push new questions
    prompts.next({/* question... */});
    prompts.next({/* question... */});
    
    // When you're done
    prompts.complete();

    You can also access fine-grained callbacks via the ui.process property on the returned object:

    inquirer.prompt(prompts).ui.process.subscribe(onEachAnswer, onError, onComplete);
  11. Configure keybindings for rawlist

    main

    You can enable alternative navigation keybindings (Vim or Emacs) globally by setting the INQUIRER_KEYBINDINGS environment variable:

    • INQUIRER_KEYBINDINGS=vim
    • INQUIRER_KEYBINDINGS=emacs
    • INQUIRER_KEYBINDINGS=vim,emacs

    To override the global setting for a specific prompt, use the theme.keybindings option within the prompt configuration.

  12. Enable Vim or Emacs keybindings for select prompts

    main

    You can enable alternative navigation keybindings globally by setting the INQUIRER_KEYBINDINGS environment variable to vim, emacs, or vim,emacs.

    Note: When Vim keybindings are enabled, type-to-search is disabled to prevent navigation keys from being interpreted as search input. You can override this per-prompt using theme.keybindings in the theme object.