UNPKG

@lenne.tech/gluegun-menu

Version:
203 lines (184 loc) 5.15 kB
import { GluegunToolbox } from 'gluegun'; /** * Menu for gluegun */ export class Menu { private optionsCache: any; /** * Constructor for integration of toolbox */ constructor(protected toolbox: GluegunToolbox) { this.optionsCache = {}; } /** * Show menu */ public async showMenu( parentCommands?: string, options?: { backLabel?: string; byeMessage?: string; cancelLabel?: string; headline?: string; helpLabel?: string; hideBack?: boolean; level?: number; setCache?: boolean; showHelp?: boolean; }, ): Promise<any> { if ( options && options.setCache && (!!options.showHelp || !!options.helpLabel || !!options.backLabel || !!options.cancelLabel || !!options.byeMessage || !!options.hideBack) ) { // save everything except level, headline & setCache this.optionsCache = { ...options }; delete this.optionsCache.level; delete this.optionsCache.headline; delete this.optionsCache.setCache; } options = { ...this.optionsCache, ...options, }; const messages = { back: options.backLabel || '[ back ]', bye: options.byeMessage || 'Take care 👋', cancel: options.cancelLabel || '[ cancel ]', help: options.helpLabel || '[ help ]', }; // Toolbox feature const { print, prompt, runtime: { brand, commands }, } = this.toolbox; // Prepare parent command parentCommands = parentCommands ? parentCommands.trim() : ''; // Process options const { headline, level } = Object.assign( { headline: parentCommands ? `${parentCommands.charAt(0).toUpperCase() + parentCommands.slice(1)} commands` : '', level: parentCommands ? parentCommands.split(' ').length : 0, }, options, ); // Headline if (headline) { print.info(print.colors.cyan(headline)); } // Get main commands let mainCommands = commands .filter( (c: any) => // Get only children of current command c.commandPath.join(' ').startsWith(parentCommands) // Get only direct children of current command && c.commandPath.length === level + 1 // Help will be added as additional command && !['help'].includes(c.commandPath[0]) // Don't show CLI brand command && !(level === 0 && [brand].includes(c.commandPath[0])), ) .map(c => c.commandPath[level] + (c.description ? ` (${c.description})` : '')) .sort(); // Additional commands if (options.showHelp !== false) { mainCommands = [messages.help].concat(mainCommands); } if (level && options.hideBack !== true) { mainCommands.push(messages.back); } mainCommands.push(messages.cancel); // Select command const { commandName } = await prompt.ask({ choices: mainCommands.slice(0), message: 'Select command', name: 'commandName', type: 'select', }); // Check command if (!commandName) { print.error('No command selected!'); return; } switch (commandName) { case messages.back: { // Get command let command = commands.filter( (c: any) => c.commandPath.join(' ') === parentCommands .trim() .replace(/\s\(.*\)$/, '') .split(' ') .slice(0, -1) .join(' '), )[0]; if (!command) { command = commands[0]; } // Run command try { this.toolbox.parameters.options.fromGluegunMenu = true; await command.run(this.toolbox); process.exit(); } catch (e) { // Abort via CTRL-C if (!e) { console.log(messages.bye); } else { // Throw error throw e; } } break; } case messages.cancel: { print.info(messages.bye); return; } case messages.help: { (print.printCommands as any)(this.toolbox, level ? parentCommands.split(' ') : undefined); break; } default: { // Get command const command = commands.filter( (c: any) => c.commandPath.join(' ') === `${parentCommands} ${commandName}`.trim().replace(/\s\(.*\)$/, ''), )[0]; // Run command try { this.toolbox.parameters.options.fromGluegunMenu = true; await command.run(this.toolbox); process.exit(); } catch (e) { // Abort via CTRL-C if (!e) { console.log(messages.bye); } else { // Throw error throw e; } } } } } } /** * Extend toolbox */ export default (toolbox: GluegunToolbox) => { // Add menu toolbox.menu = new Menu(toolbox); // Add the function to query whether the command was started from the menu toolbox.fromMenu = () => { return toolbox.parameters.options.fromGluegunMenu; }; };