hapi pal CLI
Clone or download
Latest commit 237cf20 Jul 6, 2018

README.md

hpal

hapi pal CLI

Build Status Coverage Status

Lead Maintainer - Devin Ivy

hpal was designed to help you,

  • create new hapi projects from the pal boilerplate
  • 💐 generate files for routes, extensions, models, services, etc. via haute-couture
  • 📚 search the hapi docs from the command line– plus many others such as joi and toys
  • 🐝 run custom commands defined by your server's hapi plugins

Installation

npm install -g hpal

You may also install hpal locally within a project as a dev dependency and/or invoke it using npx (which you probably already have installed, as it comes with npm v5.2+).

If you want to try the hpal CLI right now, just copy and paste this right into your terminal!

npx hpal docs --ver 17.2.0 h.response

Usage

Usage: hpal <command> <options>

Commands:

  hpal new <new-project-directory>
    e.g. hpal new ~/node-projects/new-pal-project

  hpal make [--asDir|--asFile] <haute-couture-item> [<item-name>]
    e.g. hpal make route create-user

  hpal docs[:<package-name>] [--ver x.y.z|ref] <docs-section> [<config-item>]
    e.g. hpal docs --ver 17.2.0 h.continue

  hpal run [--list] <cmd> [<cmd-options>]
    e.g. hpal run plugin-name:command-name


Options:

  -h, --help       show usage options
  -v, --version    show version information
  -d, --asDir      [make] creates new haute-couture item in a directory index file
  -f, --asFile     [make] creates new haute-couture item in a file
  -V, --ver        [docs] specifies the version/ref of the API docs to search for the given package
  -l, --list       [run] lists all available commands on your server

Commands

hpal new

hpal new <new-project-directory>
  e.g. hpal new ~/node-projects/new-pal-project

Clones the pal boilerplate, helps you fill-in initial details with npm init, pulls down the pal flavors, and leaves you prepared to make the first commit to your new project.

hpal make

hpal make [--asDir|--asFile] <haute-couture-item> [<item-name>]
  e.g. hpal make route create-user

Creates a new file for a haute-couture item with details ready to be filled-in. This is the best way to add a route, plugin, model, service, etc. to any project that uses haute-couture.

Relies on the presence of a .hc.js file in the project, even if it's empty, in order to determine the base directory of the plugin in which to write the file. If .hc.js contains amendments then those will be respected– in this way you can customize the behavior of hpal make per project. Projects created with hpal new are already configured to work with hpal make.

The --asDir and --asFile flags can be used to determine where the file is written. For a list item like routes, specifying --asFile (hpal make route --asFile) will create routes.js rather than routes/index.js. For a single item like auth/default, specifying --asDir (hpal make auth/default --asDir) will create auth/default/index.js rather than auth/default.js. When an optional <item-name> is specified then that will always place a file in the relevant directory with the name <item-name>.js. For example, hpal make route create-user will write the file routes/create-user.js.

hpal docs

hpal docs[:<package-name>] [--ver x.y.z|ref] <docs-section> [<config-item>]
  e.g. hpal docs --ver 17.2.0 h.continue

Searches the hapi API reference for the relevant section or configuration item then prints it formatted to the console.

💫 This command can also search the API reference for any package within the pal and hapijs ecosystems by specifying <package-name>, e.g. hpal docs:toys noop or hpal docs:joi any.strip.

<docs-section> can be,

When <config-item> is also specified, the first list item within the matched <docs-section> that matches text from <config-item> will be displayed on its own. For example, hpal docs request.setUrl is a long section of the docs but hpal docs request.setUrl stripTrailingSlash contains only information relevant to the stripTrailingSlash argument.

All searches are case-insensitive.

When --ver is specified as a semver version or a git ref (branch, tag, or commit), then that version of the docs will be searched. Otherwise, when inside a project the docs for the currently installed version of the given package will be searched. When not in a project and --ver is not specified, the master branch of the package's docs will be searched.

hpal run

hpal run [--list] <cmd> [<cmd-options>]
  e.g. hpal run plugin-name:command-name

Runs the command <cmd> defined by some plugin on your hapi server. If the plugin my-plugin defines a command do-the-thing, then that command can be run with hpal run my-plugin:do-the-thing. If the plugin's name is prefixed with hpal-, then hpal- may be omitted when running the command. Plugins may also have a "default" command that can be run as hpal run my-plugin.

A list of commands available on the server and their descriptions may be viewed with hpal run --list.

Upon running a command hpal will initialize the server if it is not already initialized, then stop the server when the command exits successfully.

Requirements

In order to use hpal run, hpal must be able to find your hapi server. It will look in server.js and server/index.js relative to the root of your project. That file should export a property deployment which contains a function that returns a hapi server, or a promise for a hapi server (for example, an async function).

If you're using the pal boilerplate then you should already be all set!

Here is a very basic example,

// server/index.js
const Hapi = require('hapi');
const AppPlugin = require('../app');

exports.deployment = async (start) => {

    const server = Hapi.server();

    await server.register(AppPlugin);

    if (start) {
        await server.start();
    }

    return server;
};

// Start the server only when this file is
// run directly from the CLI, i.e. "node ./server"

if (!module.parent) {
    exports.deployment(true);
}
Creating your own commands

Any hapi plugin can create commands that are runnable with hpal run! Commands are exposed to hpal using hapi's server.expose(). Inside your plugin my-plugin simply call server.expose('commands', commands), where commands is an object,

  • whose keys are command names. The name default is reserved for the command hpal run my-plugin. Camel-cased command names are converted to kebab-case, so if the key is someCommand then it is run using hpal run my-plugin:some-command.
  • whose values are either objects { command, description } or functions command where,
    • command - a function with the signature async function(server, args, root, ctx).
      • server - the initialized hapi server.
      • args - an array of all the command's CLI arguments. For example, running hpal run my-plugin --custom-flag value will result in args being ['--custom-flag', 'value'].
      • root - an absolute path to the project's root directory.
      • ctx - a context object containing some hpal internals that may be useful during testing. Also contains an error class DisplayError than can be used to indicate a "safe" failure to hpal. Throwing a DisplayError will output the error's message and exit the process with code 1, but not display a stack trace as would happen with an unexpected error.
    • description - a string description of the command displayed by hpal run --list.

For example, here is a plugin that creates a command to display the server's route table,

// hpal run route-table:show

module.exports = {
    name: 'hpal-route-table', // The hpal- prefix is ignored when running the command
    register(server) {

        server.expose('commands', {
            show(srv) {

                console.log('Route table:');

                srv.table().forEach(({ method, path }) => {

                    console.log(`  ${method} ${path}`);
                });
            }
        });
    }
};