UNPKG

10.1 kBJavaScriptView Raw
1"use strict";
2/*
3 * @adonisjs/ace
4 *
5 * (c) Harminder Virk <virk@adonisjs.com>
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10var __importDefault = (this && this.__importDefault) || function (mod) {
11 return (mod && mod.__esModule) ? mod : { "default": mod };
12};
13Object.defineProperty(exports, "__esModule", { value: true });
14exports.printHelpFor = exports.printHelp = void 0;
15const cliui_1 = require("@poppinss/cliui");
16const term_size_1 = __importDefault(require("term-size"));
17const sortAndGroupCommands_1 = require("./sortAndGroupCommands");
18/**
19 * Converts a line to rows at a specific width
20 */
21function lineToRows(text, width) {
22 const rows = [];
23 let row = [];
24 let wordsCount = 0;
25 text.split(' ').forEach((word) => {
26 if (wordsCount + (word.length + 1) > width) {
27 /**
28 * Push the number of whitespace left after the existing current
29 * and the terminal space. We need to do this, coz we at times
30 * have whitespace when the upcoming word may break into next
31 * lines
32 */
33 row.push(new Array(width - wordsCount + 1).join(' '));
34 /**
35 * Push the existing row to the rows
36 */
37 rows.push(row.join(' '));
38 /**
39 * Row is empty now
40 */
41 row = [];
42 /**
43 * Row has zero words
44 */
45 wordsCount = 0;
46 }
47 /**
48 * Increase the words count + 1. The extra one is for the
49 * whitspace between the words
50 */
51 wordsCount += word.length + 1;
52 /**
53 * Collect word inside the row
54 */
55 row.push(word);
56 });
57 /**
58 * Handle the orphan row
59 */
60 if (row.length) {
61 rows.push(row.join(' '));
62 }
63 return rows;
64}
65/**
66 * Converts the description to multiple lines fitting into
67 * a given column size
68 */
69function descriptionToRows(description, options) {
70 return lineToRows(description, options.descriptionColumnsSize)
71 .map((column, index) => {
72 return index > 0 ? `${new Array(options.nameColumnSize + 1).join(' ')}${column}` : column;
73 })
74 .join('');
75}
76/**
77 * Wraps the command arg inside `<>` or `[]` brackets based upon if it's
78 * required or not.
79 */
80function wrapArg(arg) {
81 const displayName = arg.type === 'spread' ? `...${arg.name}` : arg.name;
82 return arg.required ? `<${displayName}>` : `[${displayName}]`;
83}
84/**
85 * Returns an array of flags for displaying the help screen
86 */
87function getFlagsForDisplay(flags) {
88 return flags.map(({ name, type, alias, description }) => {
89 /**
90 * Display name is the way we want to display a single flag in the
91 * list of flags
92 */
93 const displayName = alias ? `-${alias}, --${name}` : `--${name}`;
94 /**
95 * The type hints the user about the expectation on the flag type. We only
96 * print the type, when flag is not a boolean.
97 */
98 let displayType = '';
99 switch (type) {
100 case 'array':
101 displayType = 'string[]';
102 break;
103 case 'numArray':
104 displayType = 'number[]';
105 break;
106 case 'string':
107 displayType = 'string';
108 break;
109 case 'boolean':
110 displayType = 'boolean';
111 break;
112 case 'number':
113 displayType = 'number';
114 break;
115 }
116 return {
117 displayName,
118 displayType,
119 description,
120 width: displayName.length + displayType.length,
121 };
122 });
123}
124/**
125 * Returns an array of args for displaying the help screen
126 */
127function getArgsForDisplay(args) {
128 return args.map(({ name, description }) => {
129 return {
130 displayName: name,
131 description: description,
132 width: name.length,
133 };
134 });
135}
136/**
137 * Returns an array of commands for display
138 */
139function getCommandsForDisplay(commands, aliases) {
140 return commands.map(({ commandName, description }) => {
141 const commandAliases = getCommandAliases(commandName, aliases);
142 const aliasesString = commandAliases.length ? ` [${commandAliases.join(', ')}]` : '';
143 return {
144 displayName: `${commandName}${aliasesString}`,
145 description,
146 width: commandName.length + aliasesString.length,
147 };
148 });
149}
150/**
151 * Returns the aliases for a given command
152 */
153function getCommandAliases(commandName, aliases) {
154 return Object.keys(aliases).reduce((commandAliases, alias) => {
155 if (aliases[alias] === commandName) {
156 commandAliases.push(alias);
157 }
158 return commandAliases;
159 }, []);
160}
161/**
162 * Prints help for all the commands by sorting them in alphabetical order
163 * and grouping them as per their namespace.
164 */
165function printHelp(commands, flags, aliases) {
166 const flagsList = getFlagsForDisplay(flags);
167 const commandsList = getCommandsForDisplay(commands, aliases);
168 /**
169 * Get width of longest command name.
170 */
171 const maxWidth = Math.max.apply(Math, flagsList.concat(commandsList).map(({ width }) => width));
172 /**
173 * Size of the terminal columns. Max width is the width of the command
174 * name and the extra four is whitespace around the command name.
175 *
176 * This gives the columns size for the description section
177 */
178 const descriptionColumnsSize = (0, term_size_1.default)().columns - (maxWidth + 4);
179 /**
180 * Sort commands and group them, so that we can print them as per
181 * the namespace they belongs to
182 */
183 (0, sortAndGroupCommands_1.sortAndGroupCommands)(commands).forEach(({ group, commands: groupCommands }) => {
184 console.log('');
185 if (group === 'root') {
186 console.log(cliui_1.logger.colors.bold(cliui_1.logger.colors.yellow('Available commands')));
187 }
188 else {
189 console.log(cliui_1.logger.colors.bold(cliui_1.logger.colors.yellow(group)));
190 }
191 groupCommands.forEach(({ commandName, description }) => {
192 const commandAliases = getCommandAliases(commandName, aliases);
193 const aliasesString = commandAliases.length ? ` [${commandAliases.join(', ')}]` : '';
194 const displayName = `${commandName}${aliasesString}`;
195 const whiteSpace = ''.padEnd(maxWidth - displayName.length, ' ');
196 const descriptionRows = descriptionToRows(description, {
197 nameColumnSize: maxWidth + 4,
198 descriptionColumnsSize,
199 });
200 console.log(` ${cliui_1.logger.colors.green(displayName)} ${whiteSpace} ${cliui_1.logger.colors.dim(descriptionRows)}`);
201 });
202 });
203 if (flagsList.length) {
204 console.log('');
205 console.log(cliui_1.logger.colors.bold(cliui_1.logger.colors.yellow('Global Flags')));
206 flagsList.forEach(({ displayName, displayType, description = '', width }) => {
207 const whiteSpace = ''.padEnd(maxWidth - width, ' ');
208 const descriptionRows = descriptionToRows(description, {
209 nameColumnSize: maxWidth + 4,
210 descriptionColumnsSize,
211 });
212 console.log(` ${cliui_1.logger.colors.green(displayName)} ${cliui_1.logger.colors.dim(displayType)}${whiteSpace} ${cliui_1.logger.colors.dim(descriptionRows)}`);
213 });
214 }
215}
216exports.printHelp = printHelp;
217/**
218 * Prints help for a single command
219 */
220function printHelpFor(command, aliases) {
221 if (command.description) {
222 console.log('');
223 console.log(command.description);
224 }
225 console.log('');
226 console.log(`${cliui_1.logger.colors.yellow('Usage:')} ${command.commandName} ${cliui_1.logger.colors.dim(command.args.map(wrapArg).join(' '))}`);
227 const flags = getFlagsForDisplay(command.flags);
228 const args = getArgsForDisplay(command.args);
229 /**
230 * Getting max width to keep flags and args symmetric
231 */
232 const maxWidth = Math.max.apply(Math, flags.concat(args).map(({ width }) => width));
233 /**
234 * Size of the terminal columns. Max width is the width of the command
235 * name and the extra four is whitespace around the command name.
236 *
237 * This gives the columns size for the description section
238 */
239 const descriptionColumnsSize = (0, term_size_1.default)().columns - (maxWidth + 5);
240 const commandAliases = getCommandAliases(command.commandName, aliases);
241 if (commandAliases.length) {
242 console.log('');
243 console.log(`${cliui_1.logger.colors.yellow('Aliases:')} ${cliui_1.logger.colors.green(commandAliases.join(', '))}`);
244 }
245 if (args.length) {
246 console.log('');
247 console.log(cliui_1.logger.colors.bold(cliui_1.logger.colors.yellow('Arguments')));
248 args.forEach(({ displayName, description = '', width }) => {
249 const whiteSpace = ''.padEnd(maxWidth - width, ' ');
250 const descriptionRow = descriptionToRows(description, {
251 nameColumnSize: maxWidth + 5,
252 descriptionColumnsSize,
253 });
254 console.log(` ${cliui_1.logger.colors.green(displayName)} ${whiteSpace} ${cliui_1.logger.colors.dim(descriptionRow)}`);
255 });
256 }
257 if (flags.length) {
258 console.log('');
259 console.log(cliui_1.logger.colors.bold(cliui_1.logger.colors.yellow('Flags')));
260 flags.forEach(({ displayName, displayType, description = '', width }) => {
261 const whiteSpace = ''.padEnd(maxWidth - width, ' ');
262 const descriptionRow = descriptionToRows(description, {
263 nameColumnSize: maxWidth + 5,
264 descriptionColumnsSize,
265 });
266 console.log(` ${cliui_1.logger.colors.green(displayName)} ${cliui_1.logger.colors.dim(displayType)}${whiteSpace} ${cliui_1.logger.colors.dim(descriptionRow)}`);
267 });
268 }
269}
270exports.printHelpFor = printHelpFor;