Source: classes/kickstarter.js

/**
 * @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;