nestjs-shell
TypeScript icon, indicating that this package has built-in type declarations

1.4.1 • Public • Published

NestJS Shell


travis build badge npm version badge npm bundle size license badge Coverage Status

Description

I wanted to create as simple as possible API without redundant use cases. Which allows you to create a simple command in less than a minute (counting installation time). Currently, there are a few libraries that provide something similar to this, but they violate your app's execution file with their code and require you to re-run the app's instance every time you want to execute a command.
So I decided to give you full control of where and when shell's instance should start and a way to execute commands in runtime.

For more examples, go there: https://github.com/bmstefanski/nestjs-shell-example

Features

Code sample with command that prints specified parameters to the console

  • [x] 🙉 Non-blocking runtime console
  • [x] 🚚 No dependencies
  • [x] 🤠 Simple and stable API
  • [x] 🛡️ Well tested
  • [x] 🖥️ Modifiable error messages and prompt sign
  • [x] 🖨️ Elastic output printer (you can write own printer or use any logger you want)
  • [x] 📔 Optional, required and varargs parameters
  • [ ] 📗 Travis or GitHub Actions based CI

Installation

# production use
$ yarn add nestjs-shell

# development use
$ yarn add -D nestjs-shell

Usage

Execution and registration
import { ShellModule, ShellFacade } from 'nestjs-shell'

// `ShellModule` is Global, so please put it only in your main module and it will work flawlessly in others. 
@Module({ imports: [ShellModule] })
export class YourAppMainModule implements OnApplicationBootstrap {
  constructor(private readonly shellFacade: ShellFacade) {}

  public async onApplicationBootstrap(): Promise<void> {
    // You can use it without passing any arguments and use default configuration or configure it in your own way.
    await this.shellFacade.bootstrap()

    // It does not have to be here, you can register components anywhere you want and as many times as you need. 
    this.shellFacade.registerComponents(
      new SayCommandComponent(), 
      new AnotherSecondTestCommandComponent(new SomeDependency()),
    )
  }
}
Simple example with required, optional and varargs parameters
import { ShellCommand, ShellComponent } from 'nestjs-shell'

/* Please do not put @Injectable() or any other decorator that creates a new instance of a class, 
  it may cause bugs and it is definitely not going to work the way you want. 
*/
export class SayCommandComponent extends ShellComponent {

  /* Only `name` property is required, so by default you have no prefix, no description and no pattern
    and it works fine!
  */
  /* Pattern ideology is simple:
      if your parameter name is wrapped with `<` and `>` then it's required
      if your parameter name is wrapped with `[` and `]` then it's optional
      if there is `@` sign inside any brackets (`[` or `<`) then it's varargs. 
      Same as in JavaScript varargs, they can only be placed in the last parameter.
  */
  @ShellCommand({
    name: 'say',
    prefix: '.',
    description: 'Sends a message to the console',
    pattern: '<sender> [@message]',
  })
  public async sayCommand(sender: string, message: string): Promise<string> {
    return `${sender} says: ${message || 'Nothing'}`
  }

  // There is no limit to the amount of commands in one ShellComponent.
  @ShellCommand({
    name: 'said',
    prefix: '/',
    description: 'Sends a message to the console that has been said',
    pattern: '<sender> <@message>',
  })
  /* You don't have to keep function's parameters in the same order as pattern ones. 
    They are applied by name, not order.
  */
   public async saidCommand(sender: string, message: string): Promise<string> {
    return `${sender} said: ${message}`
  }
}
Constructor dependencies
import { ShellCommand, ShellComponent } from 'nestjs-shell'

export class AnotherSecondTestCommandComponent extends ShellComponent {
  constructor(private readonly someDependency: TestDependency) {
    super()
  }

  /* You can use as much prefixes as you want.. 
    if you do not specify any then it uses the default, which is '' (empty string)
  */
  @ShellCommand({
    name: '.help',
    description: 'Displays all commands with description and usage',
  })
  public async help(): Promise<string> {
    // Method's execution context is ALWAYS set to the actual class instance and so `this` keyword works as expected.
    return [
      'Here are all available commands: ',
      '-------------------------------------',
      ...this.someDependency,
      ...this.shellFacade.getAllCommands().map((command) => {
        return `-> ${command.name} ${command.pattern} - ${command.description || 'Description not available'}`
      }),
      '-------------------------------------',
    ].join('\n')
  }
}

API specification

The library shares its methods through the facade, named ShellFacade. In the table below, you can see a brief description of each method.

import { ShellFacade } from 'nestjs-shell'
Method Description Arguments
bootstrap Enables terminal BootstrapOptions
registerComponents Adds command components to the registry ...components: ShellComponent[]
getAllCommands Returns immutable (or to be more precise: deep copy of a) collection) naught
type BootstrapOptions = {
  prompt?: string = '⤳'
  messages?: { notFound?: string; wrongUsage?: string } = { 
    notFound: 'Say what? I might have heard $input',
    wrongUsage: 'Wrong usage: $command $pattern',
  }
  shellPrinter?: ((value: any) => void) = (value: any) => console.log(value)
}

Contributions and license

Note: If you want to contribute, please keep in mind that I don't want to support various use cases, it should remain as simple as it is. So if you desire to improve code rather than add features, then I would greatly appreciate it 🙏🏻🙏🏼🙏🏽🙏🏾🙏🏿.

Nestjs-shell is MIT licensed

Package Sidebar

Install

npm i nestjs-shell

Weekly Downloads

73

Version

1.4.1

License

MIT

Unpacked Size

214 kB

Total Files

50

Last publish

Collaborators

  • bmstefanski