1

In the context of Inquirer.js, one of my question-prompts involves a validation function to check if the user-supplied Github username exists. This validation function uses an fetch function in order to check if the Github username exits.

The problem is that Inquirier repeats the prompt 3 times. Once with a ? prompt, again with a prompt, and a third time with a ? prompt, followed by the custom error message returned which lets the user know that the username did not appear to exist.

Screenshot here

This repetitive occurrence of the prompt is very confusing to the end user, and I want to know how to limit the prompt to displaying once only. I don't really understand this confusing repetitive prompt behavior to begin with.

// Include packages needed for this application

// const fs = require('fs');
import * as fs from "fs";
// const fetch = require('node-fetch');
import fetch from "node-fetch";

// const inquirer = require('inquirer');
import inquirer from "inquirer";



const validateUsername = async function (input) {
  console.log(input);

  const response = await fetch(
    `https://api.github.com/users/${input}`
  );
  // console.log(response);
  const data = await response.json();
  console.log(data.message);

  if (data.message) {
    if (data.message === "Not Found") {
      return "User was not found, please use a valid username.";
    }
  } else {
    return true;
  }
};


inquirer
  .prompt([
    {
      name: "projectName",
      message: "What the project name?",
      type: "input",
    },
    {
      name: "projectDescription",
      message: "What the project description?",
      type: "input",
    },
    {
      type: "input",
      name: "githubUser",
      message:
        "What is your Github username? (This is needed for Shields badges and is used to retrieve code size, repo size, repo file count and licence type)",

      validate: validateUsername,
    },
    {
      name: "githubRepoName",
      message:
        "What is the Github repository name? (This is needed for Shields badges and is used to retrieve code size, repo size, repo file count)",
      type: "input",
    },
    {
      name: "contribution",
      message:
        "Please provide your call to contributions and any relevant information here.",
      type: "input",
    },
    {
      type: "input",
      name: "licence",
      message: "What type of licence applies to your project?",
    },
    {
        type: "input",
        name: "twitter",
        message: "Twitter handle?  Enter without input to skip.",
    },
    {
        type: "input",
        name: "twitter",
        message: "Facebook handle?  Enter without input to skip.",
    },
  ])
  .then((answers) => {
  // do some stuff with answers
  }
shau
  • 15
  • 4
  • The doc says that validate function returns a bool. This is bad news for an async validate that must return a promise. How about stop the questions at the GitHub one, do the user name validation in the then block, from there, start a new inquirer.prompt – danh Jan 24 '23 at 02:58
  • @danh the problem in that case is coming up with some kind of loop where the question will keep displaying an error and persisting until a valid username has been provided. – shau Jan 24 '23 at 04:45
  • I took a crack at it. It might require tweaking on your part, but the gist is to isolate that one async question and validation, call it recursively on fail. – danh Jan 24 '23 at 05:04

1 Answers1

0

I haven't tried this myself, but one idea would be to isolate the question that has async validation, and make you're own validator that calls inquirer, validates and calls again...

// prompt user for gh name, check and retry if user name is invalid
async function promptAndValidateGHUser(message) {
  const answer = await inquirer.prompt([{ type: 'input', name: 'ghuser', message }])

  const response = await fetch(
    `https://api.github.com/users/${answer.ghuser}`
  );
  // console.log(response);
  const data = await response.json();
  console.log(data.message);

  if (data.message) {
    if (data.message === "Not Found") {
      return promptAndValidateGHUser("User was not found, please use a valid username.")
    }
  } else {
    return answer;
  }
}

The way to call is to build a separate promise each for the questions before the GitHub question, the GitHub question itself, and the question after.

const listA = [
  {
    name: "projectName",
    message: "What the project name?",
    type: "input",
  },
  // ...
  // up to, but not including the github question
]

const ghMessage = "What is your Github username? (This is needed for Shields badges and is used to retrieve code size, repo size, repo file count and licence type)",

const listB = [
  // the rest of the qustions
  {
    name: "contribution",
    message:
      "Please provide your call to contributions and any relevant information here.",
    type: "input",
  },
  // ...
]

Then call them in a row, like this:

async function prompts() {
  const answersA = await inquirer.prompt(listA)
  const gHubAnswer = await promptAndValidateGHUser(ghMessage)
  const answersB = await inquirer.prompt(listB)
}
danh
  • 62,181
  • 10
  • 95
  • 136
  • Good going - on first try, it seems to work! The only problem with your current code is the `,` needing to be replaced by a `;` at the end of `const ghMessage = ...` Also when the username *is* found, the code returns "undefined" in the terminal but that's my fault because `console.log(data.message);` should be removed as I only added it during testing and `data.message` only exists in Github's response when the username inputted is invalid, but otherwise the code works fine. – shau Jan 24 '23 at 10:05