UNPKG

bricks-cli

Version:

Command line tool for developing ambitious ember.js apps

222 lines (175 loc) 6.1 kB
'use strict'; var nopt = require('nopt'); var chalk = require('chalk'); var path = require('path'); var camelize = require('../utilities/string').camelize; var getCallerFile = require('../utilities/get-caller-file'); var Promise = require('../ext/promise'); var merge = require('lodash-node/modern/objects/merge'); var allowedWorkOptions = { insideProject: true, outsideProject: true, everywhere: true }; module.exports = Command; var assign = require('lodash-node/modern/objects/assign'); function Command(options) { assign(this, options); //TODO: part of default constructor this.isWithinProject = this.project.isEmberCLIProject(); this.name = this.name || path.basename(getCallerFile(), '.js'); this.aliases = this.aliases || []; // Works Property if (!allowedWorkOptions[this.works]) { throw new Error('The "' + this.name + '" command\'s works field has to ' + 'be either "everywhere", "insideProject" or "outsideProject".'); } // Options properties this.availableOptions = this.availableOptions || []; this.anonymousOptions = this.anonymousOptions || []; var self = this; this.availableOptions.forEach(function(option) { if (!option.name || !option.type) { throw new Error('The command "' + self.name + '" has an option ' + 'without the required type and name fields.'); } if (option.name !== option.name.toLowerCase()) { throw new Error('The "' + option.name + '" option\'s name of the "' + self.name + '" command contains a capital letter.'); } option.key = camelize(option.name); option.required = option.required || false; }); } Command.__proto__ = require('./core-object'); Command.prototype.description = null; Command.prototype.works = 'insideProject'; Command.prototype.constructor = Command; Command.prototype.validateAndRun = function(commandArgs) { var commandOptions = this.parseArgs(commandArgs); if (commandOptions === null) { return Promise.reject(); } this.analytics.track({ name: 'ember ', message: this.name }); return this.run(commandOptions.options, commandOptions.args); }; Command.prototype.parseArgs = function(commandArgs) { var knownOpts = {}; // Parse options var commandOptions = {}; var ui = this.ui; var commandName = this.name; var parsedOptions; var assembleAndValidateOption = function(option) { if (parsedOptions[option.name] === undefined) { if (option.default !== undefined) { commandOptions[option.key] = option.default; } else if (option.required) { ui.write('The specified command ' + chalk.green(commandName) + ' requires the option ' + chalk.green(option.name) + '.\n'); return false; } } else { commandOptions[option.key] = parsedOptions[option.name]; delete parsedOptions[option.name]; } return true; }; if (this.works === 'insideProject') { if (!this.isWithinProject) { this.ui.write('You have to be inside an ember-cli project in order to use ' + 'the ' + chalk.green(this.name) + ' command.\n'); return null; } } if (this.works === 'outsideProject') { if (this.isWithinProject) { this.ui.write('You cannot use the '+ chalk.green(this.name) + ' command inside an ember-cli project.\n'); return null; } } this.availableOptions.forEach(function(option) { knownOpts[option.name] = option.type; }); parsedOptions = nopt(knownOpts, {}, commandArgs, 0); if (!this.availableOptions.every(assembleAndValidateOption)) { return null; } for (var key in parsedOptions) { if(typeof parsedOptions[key] !== 'object') { commandOptions[camelize(key)] = parsedOptions[key]; } } var options = merge(this.settings || {}, commandOptions || {}); return { options: options, args: parsedOptions.argv.remain }; }; Command.prototype.run = function(commandArgs) { throw new Error('command must implement run' + commandArgs.toString()); }; /* Prints basic help for the command. Basic help looks like this: ember generate <blueprint> <options...> Generates new code from blueprints aliases: g --dry-run (Default: false) --verbose (Default: false) The default implementation is designed to cover all bases but may be overriden if necessary. @method printBasicHelp */ Command.prototype.printBasicHelp = function() { // ember command-name var output = 'ember ' + this.name; // <anonymous-option-1> ... if (this.anonymousOptions.length > 0) { var anonymousOptions = this.anonymousOptions; if (anonymousOptions.join) { anonymousOptions = anonymousOptions.join(' '); } output += ' ' + chalk.yellow(anonymousOptions); } // <options...> if (this.availableOptions.length > 0) { output += chalk.cyan(' <options...>'); } output += '\n'; // Description if (this.description) { output += ' ' + this.description + '\n'; } // aliases: a b c if (this.aliases.length) { output += chalk.grey(' aliases: ' + this.aliases.filter(function(a) { return a; }).join(', ') + '\n'); } // --available-option (Required) (Default: value) // ... if (this.availableOptions.length > 0) { this.availableOptions.forEach(function(option) { output += chalk.cyan(' --' + option.name); if (option.required) { output += chalk.cyan(' (Required)'); } if (option.default !== undefined) { output += chalk.cyan(' (Default: ' + option.default + ')'); } if (option.description) { output += ' ' + option.description; } output += '\n'; }); } this.ui.write(output); }; /* Prints detailed help for the command. The default implementation is no-op and should be overridden for each command where further help text is required. @method printDetailedHelp */ Command.prototype.printDetailedHelp = function() {};