UNPKG

@oclif/plugin-commands

Version:

plugin to show the list of all the commands

124 lines (123 loc) 5.25 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const core_1 = require("@oclif/core"); const _ = require("lodash"); const os_1 = require("os"); const tree_1 = require("../utils/tree"); class Commands extends core_1.Command { async run() { const { flags } = await this.parse(Commands); let commands = this.getCommands(); if (!flags.hidden) { commands = commands.filter(c => !c.hidden); } const config = this.config; commands = _.sortBy(commands, 'id').map(command => { // Template supported fields. command.description = (typeof command.description === 'string' && _.template(command.description)({ command, config })) || undefined; command.summary = (typeof command.summary === 'string' && _.template(command.summary)({ command, config })) || undefined; command.usage = (typeof command.usage === 'string' && _.template(command.usage)({ command, config })) || undefined; command.id = (0, core_1.toConfiguredId)(command.id, this.config); return command; }); if (this.jsonEnabled() && !flags.tree) { const formatted = await Promise.all(commands.map(async (cmd) => { // @ts-expect-error let commandClass = {}; try { commandClass = await cmd.load(); } catch (error) { this.debug(error); } const obj = Object.assign(Object.assign({}, cmd), commandClass); // Load all properties on all extending classes. while (commandClass !== undefined) { commandClass = Object.getPrototypeOf(commandClass) || undefined; Object.assign(obj, commandClass); } // The plugin property on the loaded class contains a LOT of information including all the commands again. Remove it. delete obj.plugin; // If Command classes have circular references, don't break the commands command. return this.removeCycles(obj); })); return _.uniqBy(formatted, 'id'); } if (flags.tree) { const tree = (0, tree_1.default)(commands, this.config.topicSeparator); if (!this.jsonEnabled()) { tree.display(); } return tree; } core_1.ux.table(commands.map(command => { // Massage some fields so it looks good in the table command.description = (command.description || '').split(os_1.EOL)[0]; command.summary = (command.summary || (command.description || '').split(os_1.EOL)[0]); command.hidden = Boolean(command.hidden); command.usage = (command.usage || ''); return command; }), { id: { header: 'Command', }, summary: {}, description: { extended: true, }, usage: { extended: true, }, pluginName: { extended: true, header: 'Plugin', }, pluginType: { extended: true, header: 'Type', }, hidden: { extended: true, }, }, Object.assign({}, flags)); } getCommands() { return this.config.commands; } removeCycles(object) { // Keep track of seen objects. const seenObjects = new WeakMap(); const _removeCycles = (obj) => { // Use object prototype to get around type and null checks if (Object.prototype.toString.call(obj) === '[object Object]') { // We know it is a "Dictionary" because of the conditional const dictionary = obj; if (seenObjects.has(dictionary)) { // Seen, return undefined to remove. return undefined; } seenObjects.set(dictionary, undefined); for (const key in dictionary) { // Delete the duplicate object if cycle found. if (_removeCycles(dictionary[key]) === undefined) { delete dictionary[key]; } } } else if (Array.isArray(obj)) { for (const i in obj) { if (_removeCycles(obj[i]) === undefined) { // We don't want to delete the array, but we can replace the element with null. obj[i] = null; } } } return obj; }; return _removeCycles(object); } } exports.default = Commands; Commands.description = 'list all the commands'; Commands.enableJsonFlag = true; Commands.flags = Object.assign({ help: core_1.Flags.help({ char: 'h' }), hidden: core_1.Flags.boolean({ description: 'show hidden commands' }), tree: core_1.Flags.boolean({ description: 'show tree of commands' }) }, core_1.ux.table.flags());