From a97398950e2ace9d4346aabeb067385d4218cc3c Mon Sep 17 00:00:00 2001 From: Pagan Gazzard Date: Tue, 28 Apr 2020 16:52:46 +0100 Subject: [PATCH] Convert lib/actions/help.coffee to javascript Change-type: patch --- automation/capitanodoc/markdown.ts | 3 + lib/actions/help.coffee | 154 ------------------------ lib/actions/help.js | 185 +++++++++++++++++++++++++++++ typings/capitano/index.d.ts | 6 +- 4 files changed, 193 insertions(+), 155 deletions(-) delete mode 100644 lib/actions/help.coffee create mode 100644 lib/actions/help.js diff --git a/automation/capitanodoc/markdown.ts b/automation/capitanodoc/markdown.ts index 600a0a64..bb570d5a 100644 --- a/automation/capitanodoc/markdown.ts +++ b/automation/capitanodoc/markdown.ts @@ -33,6 +33,9 @@ function renderCapitanoCommand(command: CapitanoCommand): string[] { if (option == null) { throw new Error(`Undefined option in markdown generation!`); } + if (option.description == null) { + throw new Error(`Undefined option.description in markdown generation!`); + } result.push( `#### ${utils.parseCapitanoOption(option)}`, option.description, diff --git a/lib/actions/help.coffee b/lib/actions/help.coffee deleted file mode 100644 index 16d16d1e..00000000 --- a/lib/actions/help.coffee +++ /dev/null @@ -1,154 +0,0 @@ -### -Copyright 2016-2017 Balena - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -### - -_ = require('lodash') -capitano = require('capitano') -columnify = require('columnify') - -messages = require('../utils/messages') -{ getManualSortCompareFunction } = require('../utils/helpers') -{ exitWithExpectedError } = require('../utils/patterns') -{ getOclifHelpLinePairs } = require('./help_ts') - -parse = (object) -> - return _.map object, (item) -> - - # Hacky way to determine if an object is - # a function or a command - if item.alias? - signature = item.toString() - else - signature = item.signature.toString() - - return [ - signature - item.description - ] - -indent = (text) -> - text = _.map text.split('\n'), (line) -> - return ' ' + line - return text.join('\n') - -print = (usageDescriptionPairs) -> - console.log indent columnify _.fromPairs(usageDescriptionPairs), - showHeaders: false - minWidth: 35 - -manuallySortedPrimaryCommands = [ - 'help', - 'login', - 'push', - 'logs', - 'ssh', - 'apps', - 'app', - 'devices', - 'device', - 'tunnel', - 'preload', - 'build', - 'deploy', - 'join', - 'leave', - 'local scan', -] - -general = (params, options, done) -> - console.log('Usage: balena [COMMAND] [OPTIONS]\n') - console.log(messages.reachingOut) - console.log('\nPrimary commands:\n') - - # We do not want the wildcard command - # to be printed in the help screen. - commands = _.reject capitano.state.commands, (command) -> - return command.hidden or command.isWildcard() - - capitanoCommands = _.groupBy commands, (command) -> - if command.primary - return 'primary' - return 'secondary' - - getOclifHelpLinePairs() - .then (oclifHelpLinePairs) -> - - primaryHelpLinePairs = - parse(capitanoCommands.primary).concat(oclifHelpLinePairs.primary).sort(getManualSortCompareFunction( - manuallySortedPrimaryCommands, - ([signature, description], manualItem) -> - signature == manualItem or signature.startsWith("#{manualItem} ") - )) - - secondaryHelpLinePairs = parse(capitanoCommands.secondary).concat(oclifHelpLinePairs.secondary).sort() - - print primaryHelpLinePairs - - if options.verbose - console.log('\nAdditional commands:\n') - print secondaryHelpLinePairs - else - console.log('\nRun `balena help --verbose` to list additional commands') - - if not _.isEmpty(capitano.state.globalOptions) - console.log('\nGlobal Options:\n') - print parse(capitano.state.globalOptions).sort() - - done() - .catch(done) - -command = (params, options, done) -> - capitano.state.getMatchCommand params.command, (error, command) -> - return done(error) if error? - - if not command? or command.isWildcard() - exitWithExpectedError("Command not found: #{params.command}") - - console.log("Usage: #{command.signature}") - - if command.help? - console.log("\n#{command.help}") - else if command.description? - console.log("\n#{_.capitalize(command.description)}") - - if not _.isEmpty(command.options) - console.log('\nOptions:\n') - print parse(command.options).sort() - - return done() - -exports.help = - signature: 'help [command...]' - description: 'show help' - help: ''' - Get detailed help for an specific command. - - Examples: - - $ balena help apps - $ balena help os download - ''' - primary: true - options: [ - signature: 'verbose' - description: 'show additional commands' - boolean: true - alias: 'v' - ] - action: (params, options, done) -> - if params.command? - command(params, options, done) - else - general(params, options, done) diff --git a/lib/actions/help.js b/lib/actions/help.js new file mode 100644 index 00000000..f9c69ef5 --- /dev/null +++ b/lib/actions/help.js @@ -0,0 +1,185 @@ +/* +Copyright 2016-2020 Balena Ltd. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import * as _ from 'lodash'; + +import * as capitano from 'capitano'; +import * as columnify from 'columnify'; +import * as messages from '../utils/messages'; +import { getManualSortCompareFunction } from '../utils/helpers'; +import { exitWithExpectedError } from '../utils/patterns'; +import { getOclifHelpLinePairs } from './help_ts'; + +const parse = object => + _.map(object, function(item) { + // Hacky way to determine if an object is + // a function or a command + let signature; + if (item.alias != null) { + signature = item.toString(); + } else { + signature = item.signature.toString(); + } + + return [signature, item.description]; + }); + +const indent = function(text) { + text = _.map(text.split('\n'), line => ' ' + line); + return text.join('\n'); +}; + +const print = usageDescriptionPairs => + console.log( + indent( + columnify(_.fromPairs(usageDescriptionPairs), { + showHeaders: false, + minWidth: 35, + }), + ), + ); + +const manuallySortedPrimaryCommands = [ + 'help', + 'login', + 'push', + 'logs', + 'ssh', + 'apps', + 'app', + 'devices', + 'device', + 'tunnel', + 'preload', + 'build', + 'deploy', + 'join', + 'leave', + 'local scan', +]; + +const general = function(_params, options, done) { + console.log('Usage: balena [COMMAND] [OPTIONS]\n'); + console.log(messages.reachingOut); + console.log('\nPrimary commands:\n'); + + // We do not want the wildcard command + // to be printed in the help screen. + const commands = capitano.state.commands.filter( + command => !command.hidden && !command.isWildcard(), + ); + + const capitanoCommands = _.groupBy(commands, function(command) { + if (command.primary) { + return 'primary'; + } + return 'secondary'; + }); + + return getOclifHelpLinePairs() + .then(function(oclifHelpLinePairs) { + const primaryHelpLinePairs = parse(capitanoCommands.primary) + .concat(oclifHelpLinePairs.primary) + .sort( + getManualSortCompareFunction(manuallySortedPrimaryCommands, function( + [signature], + manualItem, + ) { + return ( + signature === manualItem || signature.startsWith(`${manualItem} `) + ); + }), + ); + + const secondaryHelpLinePairs = parse(capitanoCommands.secondary) + .concat(oclifHelpLinePairs.secondary) + .sort(); + + print(primaryHelpLinePairs); + + if (options.verbose) { + console.log('\nAdditional commands:\n'); + print(secondaryHelpLinePairs); + } else { + console.log( + '\nRun `balena help --verbose` to list additional commands', + ); + } + + if (!_.isEmpty(capitano.state.globalOptions)) { + console.log('\nGlobal Options:\n'); + print(parse(capitano.state.globalOptions).sort()); + } + + return done(); + }) + .catch(done); +}; + +const commandHelp = (params, _options, done) => + capitano.state.getMatchCommand(params.command, function(error, command) { + if (error != null) { + return done(error); + } + + if (command == null || command.isWildcard()) { + exitWithExpectedError(`Command not found: ${params.command}`); + } + + console.log(`Usage: ${command.signature}`); + + if (command.help != null) { + console.log(`\n${command.help}`); + } else if (command.description != null) { + console.log(`\n${_.capitalize(command.description)}`); + } + + if (!_.isEmpty(command.options)) { + console.log('\nOptions:\n'); + print(parse(command.options).sort()); + } + + return done(); + }); + +export const help = { + signature: 'help [command...]', + description: 'show help', + help: `\ +Get detailed help for an specific command. + +Examples: + + $ balena help apps + $ balena help os download\ +`, + primary: true, + options: [ + { + signature: 'verbose', + description: 'show additional commands', + boolean: true, + alias: 'v', + }, + ], + action(params, options, done) { + if (params.command != null) { + return commandHelp(params, options, done); + } else { + return general(params, options, done); + } + }, +}; diff --git a/typings/capitano/index.d.ts b/typings/capitano/index.d.ts index 1a8d21a3..b23dfbb9 100644 --- a/typings/capitano/index.d.ts +++ b/typings/capitano/index.d.ts @@ -26,7 +26,7 @@ declare module 'capitano' { export interface OptionDefinition { signature: string; - description: string; + description?: string; parameter?: string; boolean?: boolean; required?: string; @@ -49,6 +49,8 @@ declare module 'capitano' { signature: Signature; options: Option[]; isWildcard(): boolean; + // You can pass whatever you want into a capitano command and it gets added as a prop + [key: string]: any; } export interface Signature { @@ -73,5 +75,7 @@ declare module 'capitano' { signature: string, callback: (e: Error, cmd: Command) => void, ) => void; + commands: Command[]; + globalOptions: OptionDefinition[]; }; }