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

promzard

v2.0.0

Published

prompting wizardly

Downloads

8,279,462

Readme

promzard

A prompting wizard for building files from specialized PromZard modules. Used by npm init.

A reimplementation of @SubStack's prompter, which does not use AST traversal.

From another point of view, it's a reimplementation of @Marak's wizard which doesn't use schemas.

The goal is a nice drop-in enhancement for npm init.

Usage

const promzard = require('promzard')
const data = await promzard(inputFile, optionalContextAdditions, options)

In the inputFile you can have something like this:

const fs = require('fs/promises')
module.exports = {
  "greeting": prompt("Who shall you greet?", "world", (who) => `Hello, ${who}`),
  "filename": __filename,
  "directory": async () => {
    const entries = await fs.readdir(__dirname)
    return entries.map(e => `entry: ${e}`)
  }
}

When run, promzard will display the prompts and resolve the async functions in order, and then either give you an error, or the resolved data, ready to be dropped into a JSON file or some other place.

promzard(inputFile, ctx, options)

The inputFile is just a node module. You can require() things, set module.exports, etc. Whatever that module exports is the result, and it is walked over to call any functions as described below.

The only caveat is that you must give PromZard the full absolute path to the module (you can get this via Node's require.resolve.) Also, the prompt function is injected into the context object, so watch out.

Whatever you put in that ctx will of course also be available in the module. You can get quite fancy with this, passing in existing configs and so on.

options.backupFile

Use the backupFile option as a fallback when inputFile fails to be read.

Class: promzard.PromZard(file, ctx, options).load()

Just like the promzard function, but the class that makes it all happen. The load method returns a promise which will resolve to the resolved data or throw with an error.

prompt(...)

In the promzard input module, you can call the prompt function. This prompts the user to input some data. The arguments are interpreted based on type:

  1. string The first string encountered is the prompt. The second is the default value.
  2. function A transformer function which receives the data and returns something else. More than meets the eye.
  3. object The prompt member is the prompt, the default member is the default value, and the transform is the transformer.

Whatever the final value is, that's what will be put on the resulting object.

Functions

If there are any functions on the promzard input module's exports, then promzard will await each of them. This way, your module can do asynchronous actions if necessary to validate or ascertain whatever needs verification.

The functions are called in the context of the ctx object.

In the async function, you can also call prompt() and return the result of the prompt.

For example, this works fine in a promzard module:

exports.asyncPrompt = async function () {
  const st = await fs.stat(someFile)
  // if there's an error, no prompt, just error
  // otherwise prompt and use the actual file size as the default
  return prompt('file size', st.size)
}

You can also return other async functions in the async function callback. Though that's a bit silly, it could be a handy way to reuse functionality in some cases.

Sync vs Async

The prompt() function is not synchronous, though it appears that way. It just returns a token that is swapped out when the data object is walked over asynchronously later, and returns a token.

For that reason, prompt() calls whose results don't end up on the data object are never shown to the user. For example, this will only prompt once:

exports.promptThreeTimes = prompt('prompt me once', 'shame on you')
exports.promptThreeTimes = prompt('prompt me twice', 'um....')
exports.promptThreeTimes = prompt('you cant prompt me again')

Isn't this exactly the sort of 'looks sync' that you said was bad about other libraries?

Yeah, sorta. I wouldn't use promzard for anything more complicated than a wizard that spits out prompts to set up a config file or something. Maybe there are other use cases I haven't considered.