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

shell

v0.5.1

Published

Full features and pretty console applications

Downloads

24,106

Readme

Shell: applications with pluggable middleware

Shell brings a Connect inspired API, Express inspired routing, and other similar functionality to console based applications.

  • Run both in shell mode and command mode
  • First class citizen for console application (arrows, ctrl-a, ctrl-u,...)
  • User friendly with history, help messages and many other plugins
  • Foundation to structure and build complex based applications
  • Command matching, parameters and advanced functionnalities found in Express routing
  • Flexible architecture based on middlewares for plugin creation and routing enhancement
  • Familiar API for those of us using Connect or Express
  • Predifined commands through plugins for Redis, HTTP servers, Cloud9, CoffeeScript, ...

Installation

Shell is open source and licensed under the new BSD license.

npm install shell

Quick start

The example below illustrate how to code a simple Redis client.

var shell = require('shell');
// Initialization
var app = new shell( { chdir: __dirname } )
// Middleware registration
app.configure(function() {
  app.use(function(req, res, next){
    app.client = require('redis').createClient()
    next()
  });
  app.use(shell.history({
    shell: app
  }));
  app.use(shell.completer({
    shell: app
  }));
  app.use(shell.redis({
    config: 'redis.conf',
    pidfile: 'redis.pid'
  }));
  app.use(shell.router({
    shell: app
  }));
  app.use(shell.help({
    shell: app,
    introduction: true
  }));
});
// Command registration
app.cmd('redis keys :pattern', 'Find keys', function(req, res, next){
  app.client.keys(req.params.pattern, function(err, keys){
    if(err){ return res.styles.red(err.message), next(); }
    res.cyan(keys.join('\n')||'no keys');
    res.prompt();
  });
});
// Event notification
app.on('quit', function(){
  app.client.quit();
});

Creating and Configuring a Shell

var app = shell();
app.configure(function() {
  app.use(shell.history({shell: app}));
  app.use(shell.completer({shell: app}));
  app.use(shell.help({shell: app, introduction: true}));
});
app.configure('prod', function() {
  app.set('title', 'Production Mode');
});

Shell settings

The constructor shell takes an optional object. Options are:

  • chdir , Changes the current working directory of the process, a string of the directory, boolean true will default to the workspace (in which case workspace must be provided or discoverable)
  • prompt , Character for command prompt, Defaults to ">>"
  • stdin , Source to read from
  • stdout , Destination to write to
  • env , Running environment, Defaults to the env setting (or NODE_ENV if defined, eg: production, development).
  • isShell , Detect whether the command is run inside a shell or as a single command.
  • noPrompt , Do not prompt the user for a command, useful to plug your own starting mechanism (eg: starting with a question).
  • workspace , Project root directory or null if none was found. The discovery strategy starts from the current working directory and traverses each parent dir looking for a node_module directory or a package.json file.

Shell settings may be set by calling app.set('key', value). They can be retrieved by calling the same function without a second argument.

var app = new shell({
  chdir: true
});
app.set('env', 'prod');
app.configure('prod', function() {
  console.log(app.set('env'));
});

As with Express, app.configure allows the customization of plugins for all or specific environments, while app.use registers plugins.

If app.configure is called without specifying the environment as the first argument, the provided callback is always called. Otherwise, the environment must match the env setting or the global variable NODE_ENV.

Middlewares and plugins

Shell is build on a middleware architecture. When a command is issued, multiple callbacks are executed sequentially until one decide to stop the process (calling res.prompt() or shell.quit. Those callbacks are called middlewares. A callback recieves 3 arguments: a request object, a response object and the next callback. Traditionnaly, request deals with stdin while response deals with stdout.

A plugin is simply a function which configure and return a middleware. Same plugin also enrich the Shell application with new routes and functions.

Shell events

The following events may be emitted:

  • "command" , listen to all executed commands, provide the command name as first argument.
  • #{command} , listen to a particular event.
  • "quit" , called when the application is about to quit.
  • "error" , called on error providing the error object as the first callback argument.
  • "exit" , called when the process exit.

Request parameter

The request object contains the following properties:

  • shell , (required) A reference to your shell application.
  • command , Command entered by the user
  • params , Parameters object extracted from the command, defined by the shell.router middleware
  • question , Ask questions with optionally suggested and default answers
  • confirm , Ask a question expecting a boolean answer

Response parameter

The response object inherits from styles containing methods for printing, coloring and bolding:

Colors:

  • black
  • white
  • yellow
  • blue
  • cyan
  • green
  • magenta
  • red
  • bgcolor
  • color
  • nocolor

Style:

  • regular
  • weight
  • bold

Display:

  • prompt , Exits the current command and return user to the prompt.
  • ln , Print a new line
  • print , Print a text
  • println , Print a text followed by a new line
  • reset , Stop any formating like color or bold
  • pad , Print a text with a fixed padding
  • raw , Return a text

Router plugin

The functionality provided by the 'routes' module is very similar to that of express. Options passed during creation are:

  • shell , (required) A reference to your shell application.
  • sensitive , (optional) Defaults to false, set to true if the match should be case sensitive.

New routes are defined with the cmd method. A route is made of pattern against which the user command is matched, an optional description and one or more route specific middlewares to handle the command. The pattern is either a string or a regular expression. Middlewares receive three parameters: a request object, a response object, and a function. Command parameters are substituted and made available in the params object of the request parameter.

Parameters can have restrictions in parenthesis immediately following the keyword, as in express: :id([0-9]+). See the list route in the example:

var app = new shell();
app.configure(function(){
  app.use(shell.router({
    shell: app
  }));
});

// Route middleware
var auth = function(req, res, next){
  if(req.params.uid == process.getuid()){
    next()
  }else{
    throw new Error('Not me');
  }
}

// Global parameter substitution
app.param('uid', function(req, res, next){
  exec('whoami', function(err, stdout, sdterr){
    req.params.username = stdout;
    next();
  });
});

// Simple command
app.cmd('help', function(req, res){
  res.cyan('Run this command `./ami user ' + process.getuid() + '`');
  res.prompt()
});

// Command with parameter
app.cmd('user :uid', auth, function(req, res){
  res.cyan('Yes, you are ' + req.params.username);
});

// Command with contrained parameter
app.cmd('user :id([0-9]+)', function(req, res) {
  res.cyan('User id is ' + req.params.id);
  res.prompt();
});

Contributors