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

ditro

v1.2.0

Published

An OOP CLI package that will ease your CLI production.

Downloads

1

Readme

Ditro

An OOP CLI package that will ease your CLI production.

This package was mainly inspired by Akairo.

Table Of Content

  1. Introduction
  2. Getting Started
    1. Setup
    2. Creating CLI
    3. Creating Commands
    4. Creating Listeners
  3. Credits

Introduction

Create CLI applications with ease like you never did before. Using similar structure to the famous known discord.js framework, Akairo.

The aim of this package is to make prompting and argument collecting easier for the developer.

It also gives the developer access to other commands in different scopes. This means you can make commands that use sub-commands, or have your own custom help command.

The package also makes use of event emitters, so you might use them for statistics purposes, or replying to the CLI user. It really opens different paths to the developer.

Getting Started

Setup

First install the package using:

$ npm i ditro
# or
$ yarn add ditro

You need to setup your project structure like this:

Project/
	package.json
	src/
		index.js
		cli/
			Cli.js
		commands/
		listeners/

Inside package.json, add a main field, with the value of src/index.js.

You can also add a bin object specifying the name of the cli as the key, and path to main file as the value.

"main": "src/index.js",
"bin": {
	"mycli": "src/index.js"
}

Note: mycli will be used as the cli bin name. It can be ran after doing npm link as "mycli ...args". You can rename it to your desire.

Creating CLI

Inside src/cli/Cli.js, you have to import DitroCli from ditro, and create a class extending DitroClass, supplying valid options, then exporting it.

You will create placeholder methods to use later on in the "Getting Started" guide.

const { DitroCli } = require('ditro');
const pkg = require('../../package.json');

class MyCli extends DitroCli {
	constructor() {
		super('My Cli Name', { pkg });
	}

	_init() {
		// placeholder method
	}

	start() {
		this._init();
		// placeholder method
	}
}

module.exports = MyCli;

Inside src/index.js you will create an instance of your custom CLI, and start it.

const MyCli = require('./cli/Cli');

const cli = new MyCli();

cli.start();

Creating Commands

First you have to create a CommandHandler instance (imported from ditro), supplying valid options and attaching it to the cli as the property MyCli#commandHandler.

CommandHandler expects two arguments, a DitroCli instance and valid options.

You can choose which commands to load or load everything in the directory you specify. We are going to stick with the latter for now.

In the MyCli#start method, we will call CommandHandler#run which parses the user input and the corresponding command.

const { DitroCli, CommandHandler } = require('ditro');
const { join } = require('path');
const pkg = require('../../package.json');

class MyCli extends DitroCli {
	constructor() {
		super('My Cli Name', { pkg });

		this.commandHandler = new CommandHandler(this, {
			directory: join(__dirname, '..', 'commands/')
		});
	}

	_init() {
		this.commandHandler.loadAll();
	}

	start() {
		this._init();
		this.commandHandler.run();
	}
}

module.exports = MyCli;

You can now create a very basic command. Create a new file src/commands/greet.js. Import Command from ditro, create a class extending Command and export it.

This command will prompt the user for their name and greet them.

Currently, there are three ways for collecting input from a user.

  • args - Uses ArgsAndFlags (due to change in future). This parses arguments passed when running the cli, for example, node start greet GamesProSeif, here, GamesProSeif is an argument.
  • flags - Also uses ArgsAndFlags (due to change in future). This parses flags passed when running the cli, for example, node start adduser --age 15 --is-male, here, age is a flag with the value of 15 and is-male is a flag with value of true.
  • prompt - Uses Inquirer, which is a very helpful package for prompting users. Their README has its documentation and relative information.

You can pass any of args, flags or prompt in the command options (second parameter when calling super), as an array of input data, each respective to their relative packages ArgsAndFlags for args and flags, Inquirer for prompt. In this example we will use prompt.

The super call expects two arguments, first is the id of the command, next is the CommandOptions.

const { Command } = require('ditro');

class GreetCommand extends Command {
	constructor() {
		super('greet', {
			aliases: ['greet', 'g'],
			description: 'Greets a user.',
			prompt: [
				{
					name: 'username',
					message: 'What is your name?'
				}
			]
		});
	}

	exec(data) {
		console.log(`Hello ${data.prompt.username}`);
	}
}

module.exports = GreetCommand;

Explaining the options:

  • aliases - Array of strings. This is what is used to run the command. The id is for storing purposes, calling the id as a command will not run it.
  • description - You can pass anything in this option, it will always be stored in Command#description. You set it as a string, or set it as an object containing multiple values. I generally do the latter, passing three properties, content; usage; examples.
  • prompt - Array of Inquirer questions.

The Command#exec method will be called passing it a CommandExecData object.

Now you should be able to run the command, node . greet.

Creating Listeners

First you have to create a ListenerHandler instance (imported from ditro), supplying valid options and attaching it to the cli as the property MyCli#listenerHandler.

ListenerHandler expects two arguments, a DitroCli instance and valid options.

You can choose which listeners to load or load everything in the directory you specify. We are going to stick with the latter again.

You will need to call ListenerHandler#setEmitter supplying valid EventEmitter instances in the format

{
	emittername: anActualEventEmitter
}

You can use emittername later inside listeners as Listener#emitter.

const { DitroCli, CommandHandler } = require('ditro');
const { join } = require('path');
const pkg = require('../../package.json');

class MyCli extends DitroCli {
	constructor() {
		super('My Cli Name', { pkg });

		this.listenerHandler = new ListenerHandler(this, {
			directory: join(__dirname, '..', 'listeners/')
		});

		this.commandHandler = new CommandHandler(this, {
			directory: join(__dirname, '..', 'commands/')
		});
	}

	_init() {
		this.listenerHandler.setEmitters({
			commandHandler: this.commandhandler
		});

		this.listenerHandler.loadAll();
		this.commandHandler.loadAll();
	}

	start() {
		this._init();
		this.commandHandler.run();
	}
}

module.exports = MyCli;

You can now head to creating your first listener. Create a new file src/listeners/end.js. Import Listener from ditro, create a class extending Listener and export it.

This listener will listen to the event Cli#end which gets emitted when the cli finishes processing, and is about to exit.

The super call expects two arguments, first is the id of the listener, next is the ListenerOptions.

const { Listener } = require('ditro');

class EndListener extends Listener {
	constructor() {
		super('end', {
			emitter: 'cli', // the event emitter
			event: 'end', // event name
			type: 'on' // either "on or "once" (default: "on")
		});
	}

	// parameters here are ones passed in EventEmitter.on('event' (...args));
	exec(successful) {
		console.log('Processing ended - successful:', successful);
	}
}

module.exports = EndListener;

successful is a boolean which indicates whether a command was ran and was successful. If you try running the cli, when it finishes processing, the Cli#end event will get emitted.

You can listen to other commands too. Events:

  • Cli
    • end
      • desc: emitted when cli finishes processing and is about to exit.
      • params: (successful: boolean)
  • CommandHandler
    • commandStarted
      • desc: emitted immediately before a command starts.
      • params: (command: Command, argv: string[], data: CommandExecData)
    • commandFinished
      • desc: emitted immediately after a command finishes successfully.
      • params: (command: Command, argv: string[], data: CommandExecData)
    • error
      • desc: emitted when the Command#exec method throws an uncatched error.
      • params: (error: Error, command: Command, argv: string[], data: CommandExecData)
    • promptStarted
      • desc: emitted immediately before the user is prompted for data.
      • params: (command: Command, argv: string[], promptData: Question[])
    • promptFinished
      • desc: emitted immediately after user answers all prompt questions.
      • params: (command: Command, argv: string[], promptData: Question[])
    • invalidCommand
      • desc: emitted when no command is found (no alias for it).
      • params: (argv: string[])

Credits

This package is authored and maintained with <3 by GamesProSeif