Inquirer - это пакет npm на основе обещаний, используемый в проектах Node для создания инструментов CLI (интерфейса командной строки) для задач на основе запросов.

В этой статье я хочу поговорить об инструменте командной строки, который мне действительно нравится использовать, и, надеюсь, кто-нибудь научится чему-то на этом пути.

Начнем с самого начала: что такое Inquirer?

Inquirer - это пакет npm на основе обещаний, используемый в проектах Node для создания инструментов CLI (интерфейса командной строки) для задач на основе запросов. Он отлично подходит для того, чтобы задавать вопросы пользователям, проверять вводимые пользователем данные и работать с полученными ответами.

Я использовал Inquirer вместе с базой данных mysql для создания инструмента командной строки, называемого «менеджером сотрудников». Он спрашивает пользователя, что он хотел бы сделать, и дает ему список вариантов. Они могут добавлять новых сотрудников, назначать роли, отделы и офисы, устанавливать зарплаты и многое другое - и все это без необходимости создавать интерфейс.

Что такое Node?

Node.js - это среда выполнения JavaScript, построенная на движке JavaScript V8 Chrome. Для получения дополнительной информации о том, что такое Node и как его настроить, щелкните здесь. Вам понадобится Node, прежде чем вы сможете использовать Inquirer.

Итак, как мне использовать Inquirer?

Рад, что ты спросил! Для этой статьи мы собираемся создать простой проект на основе Inquirer, начав с самого начала и работая до более глубоких деталей. В их документации (ссылка внизу) есть вся информация, которая вам понадобится для настройки, но давайте рассмотрим ее и здесь.

Если вы еще этого не сделали, инициализируйте npm в своем проекте, набрав в терминале в корневом каталоге проекта следующее:

npm init -y

Теперь вы готовы установить Inquirer. Введите в свой терминал следующее:

npm install inquirer

Следующим шагом является добавление библиотеки Inquirer к файлу, над которым вы работаете. Вы можете сделать это, добавив следующую строку в начало вашего кода:

const inquirer = require("inquirer")

Итак, теперь, когда мы включили в наш проект исследователя, давайте создадим наш первый запрос и запустим его. Каждый запрос начинается с одного и того же кода:

inquirer.prompt()

Итак, мы получаем доступ к библиотеке запрашивающего и используем метод подсказки, чтобы отобразить наш вопрос для пользователя. Но все гораздо сложнее - спрашивающий берет массив объектов для своих вопросов. Итак, мы открываем массив в круглых скобках, а затем объект внутри этого массива, чтобы получить что-то вроде этого:

inquirer.prompt([{}])

Каждый объект вопроса должен состоять как минимум из трех ключей:

  • имя - как вы относитесь к вопросу (и полученному ответу) позже
  • тип - что это за вопрос? (ввод, множественный выбор, числовой и т. д.)
  • сообщение - вопрос, который вы задаете пользователю

Используя эти новые знания, мы можем создать базовый вопрос, который выглядит примерно так:

inquirer
  .prompt([
    {
      name: "user_name",
      type: "input",
      message: "What is your name?",
    },
  ]);

Важно отметить, что параметром по умолчанию для «типа» является «ввод», и поэтому в этом сценарии нет необходимости, но я хотел бы включить его для ясности.

Но мы еще не закончили, мы задали вопрос, но ничего не делаем с ответом. Ответ возвращается нам в виде объекта, где ключом является свойство «name» вопроса, а ответом - его значение. Вы можете получить доступ к ответу, используя .then () с функцией обратного вызова внутри. Допустим, мы хотим вывести ответ на этот вопрос на консоль, мы могли бы использовать следующий код:

inquirer
  .prompt([
    {
      name: "user_name",
      type: "input",
      message: "What is your name?",
    },
  ])
  .then((answer) => {
    console.log("Hello " + answer.user_name);
  });

Поздравляем, вы только что написали свой первый запрос с помощью Inquirer.js. Чтобы задать этот вопрос, введите в консоль следующее:

node <filename>

Для целей этой статьи я написал свой собственный файл для демонстрации.

Давайте сделаем еще один шаг

Итак, мы задали вопрос, как задать несколько вопросов? Это так же просто, как добавить в массив еще один объект вопроса. В следующем примере я добавил в код, который мы написали ранее, с небольшими изменениями, чтобы запросить у пользователя их имя и фамилию:

inquirer
  .prompt([
    {
      name: "first_name",
      type: "input",
      message: "What is your first name?",
    },
    {
      name: "last_name",
      type: "input",
      message: "What is your last name?",
    },
  ])
  .then((answer) => {
    console.log("Hello", answer.first_name, answer.last_name);
  });

Типы вопросов

Итак, мы научились добавлять вопросы на основе ввода. Что, если мы хотим, чтобы пользователь выбирал из ряда возможных вариантов? Все, что нам нужно сделать, это изменить поле «тип» вопроса. Inquirer предлагает множество типов вопросов, из которых я использую самые распространенные:

  • Вход
  • Число
  • Подтверждать
  • Список
  • Флажок
  • Пароль

Мы уже видели некоторые вопросы о типах ввода, поэтому давайте посмотрим, что мы можем сделать с другими типами.

тип: число

Ниже приведен пример вопроса, в котором используется число и выводится результат на консоль.

inquirer
  .prompt([
    {
      name: "pet_count",
      type: "number",
      message: "How many pets do you own?",
    },
  ])
  .then((answer) => {
    console.log("You own", answer.pet_count, "pets");
  });

Он имеет встроенную проверку, которая возвращает «NaN», если вы пытаетесь ввести что-то, кроме числа (например, «восемь»). Мы можем использовать это в своих интересах и создать условное выражение, которое задает вопрос снова, если вы не указали число, превратив вопрос в такую ​​функцию:

const getPetCount = () => {
  inquirer
    .prompt([
      {
        name: "pet_count",
        type: "number",
        message: "How many pets do you own?",
      },
    ])
    .then((answer) => {
      if (!answer.pet_count) {
        console.log("That wasn't a number!");
        getPetCount();
      } else {
        console.log("You own", answer.pet_count, "pets");
    });
};
getPetCount();

Что мы сделали, так это превратили вопрос в функцию, которую можно использовать повторно, и снова вызвать вопрос, если ответ вернется как ложный. Обратите внимание: поскольку функция вопроса не вызывается сразу, нам нужно вызвать функцию ниже там, где мы ее объявили.

тип: подтвердить

Подтвердить дает пользователю простой вариант «да» или «нет» и возвращает логическое значение в качестве ответа. Следующий код - это пример того, как использовать тип подтверждения:

inquirer
  .prompt([
    {
      name: "wants_pizza",
      type: "confirm",
      message: "Do you want a free pizza?",
    },
  ])
  .then((answer) => {
    console.log(answer.wants_pizza);
  });

Пользователю задают вопрос:

Хотите бесплатную пиццу? (Да / нет)

Если вы просто ответите «Да» или «Нет», это даст вам «истина» или «ложь». Вы можете использовать это, чтобы создать серию вопросов, сохраненных в виде функций, для создания конструктора заказов на пиццу. Хочешь пиццу? Сколько пиццы вы хотите? На какой адрес мы должны доставить пиццу? Это серия вопросов с использованием типов подтверждения, числа и ввода. Но какая корочка должна быть у пиццы?

тип: список

Тип списка требует, чтобы вы добавили дополнительный ключ к вашему объекту вопроса: массив выбора. Это предоставит пользователю список вариантов, из которых можно выбрать, и сохранить свое сообщение в качестве ответа на вопрос. Этот тип полностью запрещает пользователю вводить свои собственные данные и ограничивает их выбор вашим заранее определенным списком. Вот пример:

inquirer
  .prompt([
    {
      name: "pizza_crust",
      type: "list",
      message: "Choose your crust:",
      choices: ["Thin Crust", "Stuffed Crust", "Pan"],
    },
  ])
  .then((answer) => {
    console.log(answer.pizza_crust);
  });

Пользователь сможет выбрать тип корочки из списка, и его выбор будет напечатан на консоли. Если мы будем придерживаться идеи конструктора заказов на пиццу, допустим, вы определили объект 'order' в начале документа с ключами для адреса, корочки, количества пицц и т. Д., Вы можете использовать значения из этих ответы на этот объект, затем переходите к следующему вопросу. Так что, если мы хотим выбрать несколько вариантов из списка - например, начинки для пиццы?

тип: флажок

Флажок работает аналогично списку, поскольку вы должны предоставить массив вариантов, за исключением того, что пользователь может выбрать несколько вариантов. Это будет отличный способ выбрать начинку для пиццы. Вот пример:

const toppingArray = ["Cheese", "Pepperoni", "Onions", "Peppers", "Jalapeños", "Chicken"]
inquirer
  .prompt([
    {
      name: "pizza_toppings",
      type: "checkbox",
      message: "Choose your toppings:",
      choices: toppingArray,
    },
  ])
  .then((answer) => {
    console.log(answer.pizza_toppings);
  });

Пользователю будет предложен вопрос «Выберите начинки:», а затем будет представлен список параметров, которые в этом примере я ранее определил в переменной. Пользователь может использовать пробел для выбора / отмены выбора параметров и нажать клавишу ВВОД, чтобы отправить свой ответ. После ответа ответы сохраняются в виде строк в массиве. Ответ на этот вопрос может выглядеть так:

["Cheese", "Onions", "Peppers", "Chicken"]

Интересная идея, вы можете сохранить эти ответы в переменной и использовать их позже в другом вопросе в стиле «список» или «флажок».

введите пароль

Этот пример не совсем подходит к примеру со сборщиком заказов на пиццу, но он очень важен. Тип пароля полностью скроет ввод пользователя. Никаких звездочек или затененных символов, вы ничего не увидите при вводе. Тем не менее, это невероятно полезно, поскольку любой, кто смотрит вам через плечо, даже не видит длины вашего пароля! Вот пример:

inquirer
  .prompt([
    {
      name: "user_password",
      type: "password",
      message: "Enter Password:",
    },
  ])
  .then((answer) => {
    console.log(answer.user_password);
  });

Очевидно, что вы не хотите печатать конфиденциальную информацию, которую вы только что ввели, прямо в консоль, но сделать это изначально - отличный способ проверить, что это работает. Лучшим решением в готовом продукте может быть сохранение пароля в переменной или немедленная отправка его вместе с именем пользователя для входа в службу.

Хотите создать конструктор заказов на пиццу?

Это потрясающе. Я создал супер простой пример и загрузил его на GitHub, не стесняйтесь клонировать репо и посмотреть, как все работает!

Так что еще может сделать вопрошающий?

Одна из моих любимых функций в Inquirer, когда я еще не научился разделять все свои вопросы на функции, - это «когда». В более сложном сценарии, чем построитель заказов на пиццу, вы можете добавить дополнительный вопрос, который задается только в том случае, если пользователь выбрал определенный ответ из предыдущего вопроса. Вот пример того, как использовать "когда":

inquirer
  .prompt([
    {
      name: "wants_pizza",
      type: "confirm",
      message: "Do you want a free pizza?",
    },
    {
      name: "confirm_answer",
      type: "confirm",
      message: "Are you sure?",
      when: (answers) => answers.wants_pizza === false,
    },
  ])
  .then((answers) => {
    if (answers.wants_pizza) {
      console.log("The user wants free pizza");
    } else if (answers.confirm_answer) {
      // the user definitely doesn't want pizza
    } else {
      // the user changed their mind
      // run the function to ask this question again
    } 
  });

Итак, мы можем видеть, что свойство «when» на самом деле использует функцию обратного вызова с базовым условным условием. Если ответ был ложным, спросите, уверен ли пользователь. В блоке .then () мы используем условное выражение, чтобы увидеть:

  • Если на первый вопрос был дан ответ «верно», сделайте что-нибудь.
  • Если первый ответ был неверен, если второй ответ был верным, пользователь определенно не хочет пиццу, запустите здесь какую-то функцию выхода.
  • в противном случае пользователь сказал, что не хочет пиццу, а затем передумал, поэтому его следует перенаправить к первоначальному вопросу

Важно отметить, что если пользователь говорит, что хочет бесплатную пиццу, его не спрашивают, уверены ли он - в этом сила «когда». Используя «когда», мы можем задать вопрос только, когда заданные критерии соблюдены, и пропустить его в противном случае.

Так следует ли мне разбивать запросы на функции или использовать «когда»?

На мой взгляд, у обоих есть свои варианты использования. Разделение вещей на функции отлично подходит для создания вопросов, которые можно использовать повторно, но ответы на эти вопросы ограничены областью их блоков .then (), если вы не сохраните их в переменной за пределами этой области. В случае с конструктором заказов на пиццу это было нормально, поскольку каждый вопрос привносил ценность в объект.

Конструктор заказов на пиццу с таким же успехом мог бы состоять из двух функций: одна для отображения меню "Пуск", а другая для отображения всех последующих вопросов после этого, поскольку мы всегда задаем все вопросы в этом списке.

Одним из аргументов в пользу использования функции «когда» является то, что она позволяет сэкономить на количестве написанных строк кода и сделать ваши файлы немного короче; вам не нужно писать целый блок inquirer.prompt (), а затем иметь условное выражение, которое отправит вас либо на этот вопрос, либо на следующий вопрос. Еще одно преимущество состоит в том, что, задавая вопросы таким образом, вы не теряете ответ на вопрос, который привел вас к этому моменту, изменив сферу охвата.

Значения по умолчанию

Inquirer позволяет добавлять в запросы значения по умолчанию, чтобы ускорить навигацию и делать предложения пользователю. Вот пример того, как это можно использовать:

const mediaArray = ["Facebook", "Wikipedia", "Medium"];
inquirer
  .prompt([
    {
      name: "fav_media",
      type: "list",
      message: "What is your favorite source for info?",
      choices: mediaArray,
      default: "Medium",
    },
  ])
  .then((answer) => {
    console.log(answer.fav_media);
  });

Теперь, когда пользователя спрашивают об их любимом источнике информации, выбран третий вариант - «Средний».

Это может быть очень полезно, если вы пытаетесь внедрить функциональность CRUD в свой проект, в частности, часть обновления. Вы можете перетащить существующее значение в переменную или аргумент функции и использовать его как значение по умолчанию.

Больше информации

  • Если вы хотите узнать больше о функциях Inquirer.js, вы можете просмотреть официальную документацию на npm здесь.

Кредит там, где он должен

  • Спасибо Squirrel за их статью о том, как добавлять блоки кода в статьи Medium. Эта штука выглядела беспорядком до того, как я нашла ту статью.
  • Спасибо Томасу В. Смиту за то, что научил меня всему этому (и многому другому) в первую очередь и за вычитку этой статьи.