UNPKG

node-commandline

Version:

Smart command line parser and handler for node js.

221 lines (185 loc) 6.7 kB
/* * Smart command-line parser for Node JS. * Copyright© 2012 by Daan Kets (Blackbit Consulting, http://www.blackbit.be) * Licensed under the Apache 2.0 license. */ /** * Function for evaluating if a string starts with a sub string. * @param someString The string to test. * @param subString The substring to test for. * @return {Boolean} true if the sub string is found at position 0 within someString. */ function startsWith(someString, subString) { "use strict"; return someString.indexOf(subString) === 0; } var Argument = function (name, options) { "use strict"; var self = this; self.name = name; self.required = (options && options.required) ? options.required : false; self.type = (options && options.type) ? options.type : 'boolean'; if (options && options.hasOwnProperty('order')) { self.order = Number(options.order); } self.sequenced = (options && options.sequenced) ? true : false; if (self.type === 'boolean') { self.allowedValues = [true, false]; } else if (options && options.hasOwnProperty('allowedValues')) { self.allowedValues = options.allowedValues; } self.parse = function (value) { switch (self.type) { case 'boolean': return !(value && value === 'false' && value !== 'no' && value !== '-1' && value !== 'null'); case 'number': return Number(value); case 'date': return Date.parse(value); case 'object': return JSON.parse(value); case 'string': default: return value; } }; self.toString = function () { var template = (self.order != undefined) ? "<${name}(${value})>" : "-${name}:<${value}>"; if (!self.required) { template = "[" + template + "]"; } if (self.type === 'boolean' && self.order === undefined) { template = template.replace(':', '[:'); template = template + "]"; } if (self.sequenced) { template = template.replace(':', ' '); } var value = self.type; if (self.allowedValues) { value = "{"; for (var i in self.allowedValues) { if (self.allowedValues.hasOwnProperty(i)) { value = value + self.allowedValues[i] + "|"; } } value = value.substring(0, value.length - 1); value = value + '}'; } var output = template.replace('${name}', self.name); output = output.replace('${value}', value); return output; }; }; /** * Parse a command line. Accepts any number of arguments, * @return {object} A command instance. */ function parseCommandLine() { "use strict"; var self = this; var command = {orderedArguments : []}; var sequenced = false; for (var i in arguments) { if (sequenced) { sequenced = false; continue; } if (arguments.hasOwnProperty(i)) { var argument = arguments[i]; if (startsWith(argument, '-')) { // Named argument var colonPosition = argument.indexOf(':'); if (colonPosition === -1) { colonPosition = argument.length; } var name = argument.substring(1, colonPosition); var value = undefined; if (argument.length > colonPosition + 1) { value = argument.substring(colonPosition + 1); } if (self.args.hasOwnProperty(name)) { if (self.args[name].sequenced) { if (i < arguments.length - 1) { value = arguments[Number(i) + 1]; sequenced = true; } else { if (self.args[name].required) { throw new Error('Missing required value for argument ' + name); } } } value = self.args[name].parse(value); } command[name] = value; } else { // Ordered argument command.orderedArguments.push(argument); } } } for (var argumentName in self.args) { if (self.args.hasOwnProperty(argumentName)) { argument = self.args[argumentName]; if (argument.order !== undefined && (argument.order > -1)) { if (command.orderedArguments.length >= argument.order) { command[argumentName] = command.orderedArguments[argument.order]; } else { if (argument.required) { throw new Error('Missing required argument ' + argumentName); } } } else { if (argument.required && !command.hasOwnProperty(argumentName)) { throw new Error('Missing required argument ' + argumentName); } } } } return command; } /** * The CommandLine class allows you to model a command line. After creation, it will allow you to parse a command line, * output a usage line and more. * * @constructor Constructs a new command line model/ */ var CommandLine = function (name) { "use strict"; var self = this; self.name = name; self.args = {}; self.addArgument = function (name, options) { if (options) { // Define an argument. self.args[name] = new Argument(name, options); } else { self.args[name] = new Argument(name); } return self; }; self.getArgument = function (name) { return self.args[name]; }; self.parse = parseCommandLine; self.parseNode = function () { var args = Array.prototype.slice.call(arguments); var command = self.parse.apply(this, args.slice(2, args.length)); command._executable = arguments[0]; command._script = arguments[1]; return command; }; self.toString = function () { var result = ""; for (var argumentName in self.args) { if (self.args.hasOwnProperty(argumentName)) { result = result + self.args[argumentName].toString() + " "; } } result = result.trim(); return self.name + " " + result; }; }; /** * Export the CommandLine class. * @type {Function} */ module.exports.CommandLine = CommandLine;