1

So, I have this NestJS project, and for learning purposes I want to create a command with nest-commander that would be executable on terminal (that way I could call a function from other services), also for learning purposes, whenever I call this command, it should call a function on a service file that get's a user from the database.

It would look like this :

> run myCommand -username UsernameString

Whenever that command is called from the terminal, I would call getUser() from AnotherService to find my user with that specific UsernameString. I read the docs and couldn't figure much of it, so...

  1. How do I call a command from terminal?
  2. Is it possible to call the same command within the application?
6
  • Tutorial you linked with is quite straight forward, what is not working? As for executing the command from within the app, yes - but you need to make the command in other file that can be included by both ci and application and call the same code treating @Command and application part just as user interfaces that prepares parameters given to them from different sources and executing same code in the end. Commented Feb 16, 2022 at 20:50
  • It uses crun run to run the command, but when I try using crun, it doesn't recognize the command! Commented Feb 16, 2022 at 20:59
  • the docs saids For now, we'll just assume this application is installed globally under the crun name. Commented Feb 16, 2022 at 21:05
  • Node JS:Understanding bin in package.json. Also, read the docs: nest-commander.jaymcdoniel.dev/docs/executing/local Commented Feb 16, 2022 at 21:06
  • Thanks! But in this case node ./dist/main [args] [options] running this command wound't just run my app? (it just did, but I might be a bit stupid, sorry), like: node ./dist/main sayHello just run my app Commented Feb 16, 2022 at 21:22

2 Answers 2

6

So basically if we take this example:

import { Module } from '@nestjs/common';
import { Command, CommandFactory, CommandRunner, Option } from 'nest-commander';

interface BasicCommandOptions {
  string?: string;
  boolean?: boolean;
  number?: number;
}

@Command({ name: 'basic', description: 'A parameter parse' })
export class BasicCommand extends CommandRunner {
  async run(
    passedParam: string[],
    options?: BasicCommandOptions,
  ): Promise<void> {
    if (options?.number) {
      this.runWithNumber(passedParam, options.number);
    } else if (options?.string) {
      this.runWithString(passedParam, options.string);
    } else {
      this.runWithNone(passedParam);
    }
  }

  @Option({
    flags: '-n, --number [number]',
    description: 'A basic number parser',
  })
  parseNumber(val: string): number {
    return Number(val);
  }

  @Option({
    flags: '-s, --string [string]',
    description: 'A string return',
  })
  parseString(val: string): string {
    return val;
  }

  @Option({
    flags: '-b, --boolean [boolean]',
    description: 'A boolean parser',
  })
  parseBoolean(val: string): boolean {
    return JSON.parse(val);
  }

  runWithString(param: string[], option: string): void {
    console.log({ param, string: option });
  }

  runWithNumber(param: string[], option: number): void {
    console.log({ param, number: option });
  }

  runWithNone(param: string[]): void {
    console.log({ param });
  }
}

@Module({
  providers: [BasicCommand],
})
export class AppModule {}

async function bootstrap() {
  await CommandFactory.run(AppModule);
}

bootstrap();

You can run it using that method:

ts-node ./test.ts basic -s test-value -n 1234

First you call the name of the command then the params

Sign up to request clarification or add additional context in comments.

2 Comments

I guess the main.ts starts the server and if I want to have an entry point for the command I have to make another Typescript file?
The entrypoint can be what you want. It needs to contains the 'AppModule' and you need to regoster the commands inside the 'providers' array.
1

Consider your project's nature: a versatile CLI designed for seamless terminal use. It stands alone, responsive to calls. In case my answer here does not fit you well you can try my Step by Step NestJs Commander.

First you need to create a command class for example here command-tutorial.ts

import { CommandRunner, Command, Option } from 'nest-commander';

@Command({
 name: 'basic',
 arguments: '[task]',
 description: 'A parameter parse',
 })
export class CommandTutorial extends CommandRunner {
   constructor() {
   super();
 }

async run(
  passedParams: string[],
  options?: Record<string, any>,
 ): Promise<void> {
  console.log('CLI Params', passedParams);
  console.log('CLI Options', options);
   return Promise.resolve(undefined);
}
 @Option({
  flags: '-n, --number [number]',
  description: 'A basic number parser',
 })
 parseNumber(val: string): number {
   return Number(val);
}
}

then inside the app.module.ts import this command

import { Module } from '@nestjs/common';
import { CommandTutorial } from './command-tutorial';
@Module({
  imports: [],
  controllers: [],
  providers: [CommandTutorial],
  })
export class AppModule {}

inside your main.ts you need to add the shebang on the top of you of your code and plus change the bootstrap function

#!/usr/bin/env node
import { AppModule } from './app.module';
import { CommandFactory } from 'nest-commander';

async function bootstrap() {
   await CommandFactory.run(AppModule, {
   logger: ['warn', 'error'],
  });
}
bootstrap();

for testing your app it is so easy just run the following command

ts-node main.ts basic argument -n 1

and check the result inside your CMD

now to run it with a terminal prompt you need to update your package.json and add the bin script

"bin": {
  "tutorial": "dist/main.js"
}

or

"bin": {
  "tutorial": "./dist/main.js"
}

"tutorial" will be your command you can change it to whatever you want

and run the following command chmod +x ./dist/main.js (MAC OS check it is alternative in Windows/Unix)

then inside your NodeJs Project or NestJs Project install this as module using

  • npm i path-to-your-nest-command-cli-directory

if you would like to be globally inside your machine

  • npm i g path-to-your-nest-command-cli-directory

Now run tutorial basic argument -n 1 inside your cmd or terminal you should get

CLI Params: argument CLI Option: {n:1}

All the best

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.