UNPKG

bpmn-js-cli

Version:

A command-line interface for bpmn-js

239 lines (186 loc) 4.62 kB
import { isArray, isNumber, isString, isFunction, forEach } from 'min-dash'; function asArray(args) { return Array.prototype.slice.call(args); } function asParam(parse) { return function(name, options) { return { name: name, parse: function(val) { return parse(val, options || {}); } }; }; } function StringParser() { return function(arg, options) { // support variable arguments if (isArray(arg)) { arg = arg.join(' '); } if (arg !== '' && !arg) { if (options.defaultValue) { return options.defaultValue; } else { throw new Error('no value given'); } } else { return arg; } }; } function BooleanParser() { return function(arg, options) { if (!arg) { if (options.defaultValue) { return options.defaultValue; } if (options.optional) { return undefined; } throw new Error('no value given'); } else { return arg && arg !== 'false'; } }; } function NumberParser() { return function(arg, options) { if (arg !== 0 && !arg) { if (options.defaultValue) { return options.defaultValue; } else { throw new Error('no value given'); } } else { return isNumber(arg) ? arg : parseFloat(arg, 10); } }; } /** * The CLI. * * @param {Object} config * @param {didi.Injector} injector */ export default function Cli(config, injector) { this._commands = {}; this._params = {}; this._injector = injector; this._registerParsers(); this._registerCommands(); this._bind(config); } Cli.$inject = [ 'config', 'injector' ]; // reset prototype (ain't gonna inherit from object) Cli.prototype = {}; // helpers ////////////////////////// Cli.prototype._bind = function(config) { if (config.cli && config.cli.bindTo) { console.info('bpmn-js-cli is available via window.' + config.cli.bindTo); window[config.cli.bindTo] = this; } }; Cli.prototype._registerParser = function(name, Parser) { var parser = this._injector.invoke(Parser); // must return a function(val, options) -> result if (!isFunction(parser)) { throw new Error( 'parser must be a Function<String, Object> -> Object' ); } this._params[name] = asParam(parser); }; Cli.prototype._registerCommand = function(name, Command) { var command = ( isFunction(Command) ? this._injector.invoke(Command) : Command ); command.args = command.args || []; this._commands[name] = command; var self = this; this[name] = function() { var args = asArray(arguments); args.unshift(name); return self.exec.apply(self, args); }; }; Cli.prototype._registerParsers = function() { this._registerParser('string', StringParser); this._registerParser('number', NumberParser); this._registerParser('bool', BooleanParser); }; Cli.prototype._registerCommands = function() { var self = this; // special <help> command this._registerCommand('help', { exec: function() { var help = 'available commands:\n'; forEach(self._commands, function(c, name) { help += '\n\t' + name; }); return help; } }); }; Cli.prototype.parseArguments = function(args, command) { var results = []; var last = command.args.length - 1; forEach(command.args, function(c, i) { var val; // last arg receives array of all remaining parameters if (i === last && args.length > command.args.length) { val = args.slice(i); } else { val = args[i]; } try { results.push(c.parse(val)); } catch (e) { throw new Error('could not parse <' + c.name + '>: ' + e.message); } }); return results; }; Cli.prototype.exec = function() { var args = []; // convert mixed whitespace separated string / object assignments in args list // to correct argument representation asArray(arguments).forEach(function(arg) { if (isString(arg)) { args = args.concat(arg.split(/\s+/)); } else { args.push(arg); } }); var name = args.shift(); var command = this._commands[name]; if (!command) { throw new Error( 'no command <' + name + '>, ' + 'execute <commands> to get a list of available commands' ); } var values, result; try { values = this.parseArguments(args, command); result = command.exec.apply(this, values); } catch (e) { throw new Error( 'failed to execute <' + name + '> ' + 'with args <[' + args.join(', ') + ']> : ' + e.stack ); } return result; };