UNPKG

moleculer-repl

Version:
160 lines (140 loc) 4.06 kB
"use strict"; const _ = require("lodash"); /** * Returns the list of versioned services * * @param {import("moleculer").ServiceBroker} broker * @returns {Array<String>} */ function versionedServicesAutocomplete(broker) { let services = broker.registry.getServiceList({ onlyLocal: true, onlyAvailable: true, skipInternal: true, withActions: true, withEvents: true }); // Return only the names return services.map(service => service.fullName); } /** * Returns the list of nodes and their actions in the following format "<nodeID> <actionName>" * * @param {import("moleculer").ServiceBroker} broker * @returns {string[]} */ function nodeIdActionNameAutocomplete(broker) { /** @type {string[][]} */ const nested = _.compact( broker.registry.getNodeList({ onlyAvailable: true, withServices: true }).map(node => { // Get actions of the node let actionList = node.services.map(svc => { return Object.values(svc.actions).map(action => { return action.name; }); }); actionList = _.flatten(actionList); // Create "<nodeID> <action name> command for autocomplete return actionList.map(actionName => `${node.id} ${actionName}`); }) ); return _.uniq(_.flatten(nested)); } /** * Returns the list of available actions * * @param {import("moleculer").ServiceBroker} broker * @returns {Array<String>} */ function actionNameAutocomplete(broker) { return _.uniq( _.compact( broker.registry .getActionList({}) .map(item => (item && item.action ? item.action.name : null)) ) ); } /** * Returns the list of available events * * @param {import("moleculer").ServiceBroker} broker * @returns {Array<String>} */ function eventNameAutocomplete(broker) { return _.uniq( _.compact( broker.registry .getEventList({}) .map(item => (item && item.event ? item.event.name : null)) ) ); } /** * Returns list of available commands * @param {import('commander').Command} program * @returns {String[]} Available commands */ function getAvailableCommands(program) { const nested = program.commands.map(entry => [entry.name(), ...entry.aliases()]); return /** @type {string[]} */ (_.flatten(nested)); } /** * Given a line from terminal generates a list of suggestions * * @param {String} line * @param {import("moleculer").ServiceBroker} broker * @param {import('commander').Command} program * @returns {[String[], String]} List of suggestions. More info: https://nodejs.org/api/readline.html#use-of-the-completer-function */ function autocompleteHandler(line, broker, program) { let [command, ...rest] = line.split(" "); const availableCommands = getAvailableCommands(program); // Empty line. Show all available commands if (!command) { return [availableCommands, line]; } // Check if command value is complete if (!availableCommands.includes(command)) { // Unknown or incomplete command. Try to provide a suggestion const hits = availableCommands.filter(c => c.startsWith(command)); // Show all completions if none found return [hits.length ? hits : availableCommands, line]; } // From here we already know what command will be executed // let completions = []; switch (command) { case "cache": { completions = ["keys", "clear"]; break; } case "listener": { completions = ["add", "remove", "list"]; break; } case "bench": case "call": { completions = actionNameAutocomplete(broker); break; } case "broadcast": case "broadcastLocal": case "emit": { completions = eventNameAutocomplete(broker); break; } case "dcall": { completions = nodeIdActionNameAutocomplete(broker); break; } case "destroy": { completions = versionedServicesAutocomplete(broker); break; } } completions = completions.map(entry => `${command} ${entry}`); // Match the command + action/event name against partial "line" value let hits = completions.filter(c => c.startsWith(line)); return [hits.length ? hits : completions, line]; } module.exports = { autocompleteHandler, getAvailableCommands };