/**
* @author ruckola
* @class
* @classdesc Creates a new instance of the Controller class. This controller object
* has an object of type CommandContext, that will be passed into the command object
* when the controller executes the command.
* The kickstarter can run a macro command or a single command. Both command types will
* return a promise.
* @property {Controller} this.ctrl - A new controller object.
* @property {commandContext} this.ctxt - The commandContext object that comes with a new controller.
*/
class Kickstarter {
/**
* @constructor
* @param {string} action - The name of a single command.
* @param {number} action - The id of a macro (available in the user configuration file).
* @description Creates an instance of the controller class and passes the
* value of the action parameter to the context.<br>
* The kickstarter can run in three different modes.
* <pre>
* Single command mode:
* -The action parameter must be the name of the command,
* without the .js file extension, so like this: <mycommand>.
* -Namespaces are allowed and must be included, like this:
* <my/namespace/mycommand>.
*
* Macro command mode:
* -The action parameter must be the id of the macro,
* as specified in the user configuration file.
* -Namespaces are allowed and can be used in two ways:
* 1) When all subcommands are in the same namespace,
* specify a namespace, by putting a namespace key
* into the macro configuration like this:
* <"namespace": "my/namespace/mycommand">
* 2) When subcommands have different namespaces,
* set the namespace key to 'false' like this:
* <"namespace": false>
* or remove it completely. Then set the namespace
* for each subcommand individually in the cmdSequence
* key like this:
* <my/namespace/subcommand>
*
* Test mode:
* - if the action parameter is set to 'testMode', then
* the helper.modConfig() will load the configuration for the test environment.
* - the environment is located in the 'test'-directory: ./test/testEnv'
* </pre>
* The constructor also reads the module configuration file, in which
* the following relative paths must be specified:
* <pre>
* {
* "userCommandsRootDir":"my/project/commands",
* "userConfigFile":"my/project/config/config.json",
* "userHelperDir":"my/project/helper"
* }
* </pre>
*/
constructor(action = this.throwIfMissing()) {
var Controller = require("../core/controller");
var Helper = require("../core/helper");
var modConfig = {};
this.ctrl = new Controller;
this.ctxt = this.ctrl.getContext();
if(!action){
try {
throw new Error
} catch (error) {
}
}
if (typeof (action) === 'string') {
this.ctxt.parameters.action = action;
} else if (typeof (action) === 'number') {
this.ctxt.parameters.macroID = action;
}
if (action === 'testMode') {
modConfig = Helper.getModConfig(true);
} else {
modConfig = Helper.getModConfig();
}
if (modConfig.userConfigFile) {
this.ctxt.parameters.userConfigFile =
modConfig.userConfigFile;
try {
var usrCfg = require(modConfig.userConfigFile);
}
catch (e) {
console.error(e);
}
this.ctxt.parameters.userConfiguration =
usrCfg;
}
if (modConfig.userHelperDir) {
this.ctxt.parameters.userHelperDir =
modConfig.userHelperDir;
}
if (modConfig.userCommandsRootDir) {
this.ctxt.parameters.userCommandsRootDir =
modConfig.userCommandsRootDir;
}
// TODO: Implement a check on each macro config.
// warn when a subcommand in a command sequence
// does not have a corresponding config entry
// for itself.
Helper.validateUserConfiguration();
}
/**
* @method
* @description Delegates the execution of the command to the controller.
* @returns {Promise} - a promise with a commandResult object as its value.<br>
* If you run a macro with multiple subcommands, the commandResult object of each subcommand,<br>
* will be included in the array of the 'data'-property. (See also: {@link CommandResult})<br><br>
* <em>Note:</em><i>
* This nesting of commandResult objects can go very deep, since it is possible to spawn
* kickstarters (read: start other macro's) from subcommands as well.<br>
* By doing this, you will allow to run some commands asynchronous in relation to each other,
* but still your client can depend upon the output.<br>
* This is because everything finally resolves into just one promise, that will be returned to the client.</i>
*/
run() {
return this.ctrl.process();
}
throwIfMissing() {
throw new Error("Kickstarter requires an 'action' parameter.");
}
}
module.exports = Kickstarter;