xpepermint / rawcmd-framework

Framework for building command-line user interfaces in NodeJS

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Rawcmd Framework

Build Status codecov

Rawcmd allows for building command-line user interfaces in NodeJS. It's a lightweight and open-source framework, written with TypeScript. It's actively maintained, well tested and already used in production environments. The source code is available on GitHub where you can also find our issue tracker.

Introduction

Rawcmd represents a scaffold for creating reach command-line user interfaces in NodeJS. The purpose of this framework is to provide the logic and methods for building custom command-line utilities.

Installation

Run the command below to install the package.

$ npm install --save @rawcmd/core
$ npm install --save @rawcmd/typewriters // OPTIONAL

This package uses promises thus you need to use Promise polyfill when promises are not supported.

Usage

Below we explain some of the most important features that this framework provides. Please check the API section to see a complete list of features.

Defining commands

Command represents the entry point of your command-line program.

import { Command } from '@rawcmd/core';

const command = new Command({
  resolver() {
    console.log('Hello World!');
  },
});

command.perform(); // prints "Hello World!"

By nesting commands we can create a tree of commands.

const command = new Command({ // entry point (root)
  commands: [
    new Command({ // first level
      name: 'list',
      resolver() {
        console.log('List all!');
      },
      commands: [
        new Command({ // second level
          name: 'latest',
          resolver() {
            console.log('List latest!');
          },
        }),
      ],
    }),
  ],
});

command.perform('list'); // prints "List all!"
command.perform('list', 'latest'); // prints "List latest!"

Processing options

Every command accepts options which we can use to adjust command execution. We can apply parsers and validators to each option to make sure the resolver receives expected input data. In case one of validators fail, the resolver throws ValidationError class instance.

const command = new Command({
  options: [
    {
      name: 'name',
      alias: 'n',
      parse: { // check @rawmodel/parsers for predefined parsers
        resolver(v) { return `${v}` }, // transform value to string
      },
      validate: [ // check @rawmodel/validators for predefined validators
        {
          code: 4220001,
          resolver() { return false; }, // return `false` so validation fails
        },
      ],
    },
  ],
  resolver(input) {
    console.log(input); // => { "options": { "name": "John" }, "tail": "arg1 arg2" }
  },
});

command.perform('--name=John', '--', 'arg1', 'arg2').catch((error) => {
  console.log(error); // => { "code": 4220001, "name": "ValidationError", "message": "Validation failed." }
});

The validation is handled by the powerful RawModel framework where you will find more details regarding data validation.

Printing messages

Every command provides methods for printing messages to the output stream. By default the output stream is set to process.stdout.

const command = new Command({
  resolver() {
    this.print('Hello World!'); // prints message with EOL
  },
});

Messages can be formated through different typewriters which can be found in @rawcmd/typewriters package.

import { textTypewriter } from '@rawcmd/typewriters'; 

const typewriteGreen = textTypewriter({
  bold: true,
  color: TextColor.GREEN,
});

const command = new Command({
  resolver() {
    this.write( // prints "100%" as strong green text
      typewriteGreen('100'),
      typewriteGreen('%'),
    );
    this.break(); // prints EOL
  },
});

Handling errors

Errors should be triggered directly within resolver and handled outside command class.

import { RuntimeError } from '@rawcmd/core';

const command = new Command({
  resolver() {
    throw new RuntimeError(500001);
  },
});

command.perform().catch((error) => {
  command.print('Error', error.message);
});

Beside the ValidationError which we already mentioned above, RuntimeError can be thrown when an error accures. It's advised that you use your custom errors which extend GenericError class.

Creating executable file

TODO

API

NOTE: This section covers only the end-user related classes and methods. Please read the source code to explore more details.

@rawcmd/core

Command(recipe, config)

Command class for defining executable command.

Option Type Required Default Description
recipe.name String No - Command name.
recipe.description String No - Command description.
recipe.options.$.name String Yes - Option name.
recipe.options.$.alias String No - Option alias.
recipe.options.$.description String No - Option description.
recipe.options.$.setter Function No - Custom option setter. Check Rawmodel for details.
recipe.options.$.getter Function No - Custom option getter. Check Rawmodel for details.
recipe.options.$.parser Object No - Option parser configuration. Check Rawmodel for details.
recipe.options.$.defaultValue String, Function No - Option default value. Check Rawmodel for details.
recipe.options.$.emptyValue String, Function No - Option empty value. Check Rawmodel for details.
recipe.options.$.validators ValidatorRecipe[] No - List of option validators. Check Rawmodel for details.
recipe.options.$.handlers HandlerRecipe[] No - List of option error handlers. Check Rawmodel for details.
recipe.commands Command[] No - List of sub commands.
recipe.resolver Function No - Command resolver.
config.parent Command No - Parent command class instance.
config.context Context No - Arbitrary context data.
config.spinwriter Spinwriter No - Spinwriter class instance.
config.typewriter Typewriter No - Typewriter class instance.

Command.prototype.break(): Command

Writes EOL to outptu stream.

Command.prototype.description: String

Returns command description.

Command.prototype.getAncestors(): Command[]

Returns a list of all parent command instances.

Command.prototype.getContext(): Context

Returns custom context defined at initialization time.

Command.prototype.getParent(): Command

Returns parent command instance.

Command.prototype.getSpinwriter(): Spinwriter

Returns spinwriter class instance.

Command.prototype.getTypewriter(): Typewriter

Returns typewriter class instance.

Command.prototype.name: String

Returns command name.

Command.prototype.perform(...args): Promise

Performs a command based on the provided command-line arguments.

Option Type Required Default Description
args String[] No - List of command-line arguments (e.g. ['init', '--name=foo']). Expects parameters as process.argv.slice(2).

Command.prototype.print(...messages): Command

Writes messages to outptu stream with EOL at the end.

Option Type Required Default Description
messages string[] Yes - List of arbirary messages.

Command.prototype.spin(message): Command

Writes a message to outptu stream as spinner animation.

Option Type Required Default Description
message string Yes - Arbirary message.

Command.prototype.write(...messages): Command

Appends outptu stream with messages.

Option Type Required Default Description
messages string[] Yes - List of arbirary messages.

EOL: String

Holds a new-line character.

@rawcmd/typewriters

commandsTypewriter(options): Function(command)

Returns a function which builds a string showing a list of all available sub commands with descriptions.

Option Type Required Default Description
options.title String No Commands Section title.
options.paddingWidth Integer No 5 Dotted padding size.
options.totalWidth Integer No 80 Allowed horizontal width.
command Command Yes - Command class instance.

contentsTypewriter(options): Function(data)

Returns a function which builds an arbitrary table of contents string with names and decriptions

Option Type Required Default Description
options.paddingWidth Integer No 5 Dotted padding size.
options.totalWidth Integer No 80 Allowed horizontal width.
data String[][] Yes - List of arrays with names and descriptions.

errorTypewriter(options): Function(error)

Returns a function which builds an arbitrary table of contents string with names and decriptions

Option Type Required Default Description
options.code Integer No 500000 Default error code.
options.message String No Text Default error message.
options.title String No Error Section title.
options.totalWidth Integer No 80 Allowed horizontal width.
error Error Yes - Arbitrary error object.

helpTypewriter(options): Function(data)

Returns a function which builds a string describing command abilities and other useful information.

Option Type Required Default Description
options.totalWidth Integer No 80 Allowed horizontal width.
command Command Yes - Command class instance.

linksTypewriter(options): Function(command)

Returns a function which builds a string representing a list of all usefull support references and links.

Option Type Required Default Description
options.title String No Links Section title.
options.paddingWidth Integer No 5 Dotted padding size.
options.totalWidth Integer No 80 Allowed horizontal width.
command Command Yes - Command class instance.

logTypewriter(options): Function(message, namespace, date)

Returns a function which builds a string for displaying log message.

Option Type Required Default Description
options.message String Yes Arbitrary log message.
options.namespace String No - Namespace string.
options.date Date No Date Date object instance.
options.totalWidth Integer No 80 Allowed horizontal width.

optionsTypewriter(options): Function(command)

Returns a function which builds a string representing a list of all available command options with descriptions.

Option Type Required Default Description
options.title String No Options Section title.
options.paddingWidth Integer No 5 Dotted padding size.
options.totalWidth Integer No 80 Allowed horizontal width.
command Command Yes - Command class instance.

rowTypewriter(columns, options): Function(data)

Converts data to stringified table.

Option Type Required Default Description
columns.$.index Integer Yes - Column index.
columns.$.width Integer No - Columns width.
columns.$.textAlign String No left Text alignment.
columns.$.textLength Integer No - Text truncation size.
columns.$.textWrap Boolean No true Wrapps long strings into multiple rows.
columns.$.truncate Integer No - Truncate text at position.
options.separatorSymbol String No - Custom string between columns.
options.truncationSymbol String No - Custom truncation simbol.
data Any[][] Yes - Two dimensional table of arbitrary data. Values are automatically converted to string.
import { rowTypewriter } from '@rawcmd/typewriters';

const typewriter = rowTypewriter([
  { index: 0, width: 20 },
  { index: 1, width: 60 },
], {
  separatorSymbol: ' | ',
});
const text = typewriter([
  'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
  'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
]);

summaryTypewriter(options): Function(command)

Returns a function which builds a string representing command summary text.

Option Type Required Default Description
options.title String No Summary Section title.
options.totalWidth Integer No 80 Allowed horizontal width.
command Command Yes - Command class instance.

textTypewriter(options): Function(data)

Applyes styles to the provided string.

Option Type Required Default Description
options.reset Boolean No - Resets current styles.
options.bold Boolean No - Makes text brighter.
options.dim Boolean No - Makes text darker.
options.underline Boolean No - Makes text underlined.
options.inverse Boolean No - Inverses font and background colors.
options.color String No - Applyes a color to text.
options.background Boolean No - Applyes a color to background.
data String Yes - Arbitrary string.
import { TextAlign, TextColor, textTypewriter } from '@rawcmd/typewriters';

const typewriter = textTypewriter({
  align: TextAlign.RIGHT,
  bold: true,
  color: TextColor.MAGENTA
});
const text = typewriter('Hello World!');

titleTypewriter: Function(text)

Returns a function which builds a string representing section title.

Option Type Required Default Description
options.totalWidth Integer No 80 Allowed horizontal width.
text String Yes - Arbitrary text.

usageTypewriter: Function(command)

Returns a function which builds a string showing how the command should be used with examples.

Option Type Required Default Description
options.title String No Usage Section title.
options.totalWidth Integer No 80 Allowed horizontal width.
command Command Yes - Command class instance.

Packages

Package Description Version
@rawcmd/core Core framework logic. NPM Version
@rawcmd/text Text manipulation methods. NPM Version
@rawcmd/typewriters Collection of typewriters. NPM Version
@rawcmd/utils Helper functions. NPM Version

Contributing

See CONTRIBUTING.md for how to help out.

Licence

See LICENSE for details.

About

Framework for building command-line user interfaces in NodeJS

License:MIT License


Languages

Language:TypeScript 100.0%