What are commands and why should I use them?

You can more or less compare a command with a npm package. It is re-usable code that is preferably responsible for just one thing, and usually works pretty well. The main difference between a npm package and a command, is that npm packages are not necessarily made to build upon each other directly, while commands do. Also a package can contain multiple files, while a command is just a node module, that exports one and only one class.

So commands are like Lego? Yes and no. Yes, because commands can be chained and they can build upon each others output. And no, because although all commands return an object with a similar structure,  the value(s) of their output can be of any type. It depends purely upon their implementation. This means that not all commands are compatible with each other.
Another thing worth mentioning, is that incompatible commands can still be part of the same macro, as long as they depend solely upon their configuration and context parameters, instead of the output of other, incompatible commands.

But all this might be a little vague, so head on to some real code, to show what a command looks like and what it is expected to do.

My first command

All commands go into the commands directory of your project. So lets create a new file in which we will write our first class:

(Please note, that camelCase is used for naming commandFiles, and PascalCase is used for ClassNames).

Below, you can see the minimal code required to build a command. Although it does absolutely nothing, it is a valid command, that can be run.

First I require the abstract class ‘Command’ from the macro-command package. Then I create my class ‘FirstCommand’, which extends the required ‘Command’ class. My class only has one method called ‘execute’, which takes only one parameter called ‘context’. What is important here, is that you can create as many new methods as you like, as long as there is one method called ‘execute’ that takes one parameter. The name of the parameter is not important. However, the value that gets passed in by the controller, is by far the most important object of the macro-command. It is the ‘commandContext’, which holds all the configurations and values of any preceding commands. You will use it a lot.

The return value of any command class must be a new promise, which you can either resolve or reject. When you resolve or reject the promise, it is a convention to pass in a ‘commandResult’ object. The constructor of the Command class already created one for you, so it is available as a private property called ‘result’.
When you have worked with promises before, you already know that

ain’t gonna work inside a new promise definition. ‘This’ is not accessible, and therefore you have to assign ‘this’ to a new variable.

Now ‘this’ is accessible through ‘self’ inside the scope of the new promise.
And last but not least, we have to make sure that the module exports the class.

What is a commandResult object?

A command result is an object created from this class:

As you can see it has three properties (or fields if you like) and it is pretty obvious what they’re meant for:

  1. cmd – is used to store the name of the current command. Since version v1.0.10 this is done automatically by the Command-class itself.
  2. data – is supposed to store an array of objects. So, anything that you’d like your command to return as its value. It can be just one string or number, but also thousands of blobs or whatever… The reason that it is stored into an array, is because of the build-in functions that come with arrays. If it would be an object, you’ll have to implement these functionalities yourself somehow.
  3. msg – is used to say something about the data. Meta-data so to speak.

As said before, the commandResult object comes with the abstract ‘Command’ so you do not have to require it yourself. It is already there whenever you extend the ‘Command’ class. You can access it from within your own commands by using the private property below:

Finish our first command

Ok, lets make our first command do at least something instead of absolutely nothing. Lets do some simple calculation like (n * 100 = x), where ‘n‘ is a variable that we pass in via a configuration file. ‘x‘ will be the value that is returned by the resolved promise.

As you can see, I have assigned the ‘context‘ object (that is injected by the controller) to ‘this. context‘. In this example it is not really necessary, but if my class would have had more methods, then each of them would instantly have access to the context as well. So, it is just a good habit, nothing special.

The next new thing is that I retrieve the value of ‘n‘ from

The macro-command will always add any new parameters to ‘context.parameters‘. How, when and were this happens is not important for now. Just remember that it does and that the configuration of the current command will always be available through the ‘cmdConfiguration‘-key.
(This is both true for single-commands and macro’s.)
Then I use ‘n‘ to calculate ‘x‘ and push ‘x‘ to the ‘result.data‘ which is of type array.
The ‘result.cmd’ is set automatically to the current class name.
The ‘result.msg‘ is set to a string value, showing the calculation of ‘x‘.

Summary

We have successfully created a new command, that is ready to be used by any application that uses the macro-command package. Of course the command lacks several things like error checking, input validation and rejecting the promise, but that was left out on purpose. I’ve showed you how to build a command with the bare minimum of code, to keep the example as simple as possible.
Before we can actually run the command, we still have some work to do. We need to configure it first and then we have to create an app that runs the command. This will be explained in the next part of this tutorial. So, see you on the next page…

< Previous part | Next part >