mirror of
https://github.com/balena-io/balena-cli.git
synced 2025-01-19 03:06:29 +00:00
abf573fa47
zero in device UUID). This commit is fairly chunky because it adds the oclif dependency for the first time, and refactors the CLI help and docs generation code to accommodate both Capitano and oclif. Change-type: patch Signed-off-by: Paulo Castro <paulo@balena.io>
150 lines
4.1 KiB
TypeScript
150 lines
4.1 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2019 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 { flagUsages } from '@oclif/parser';
|
|
import * as ent from 'ent';
|
|
import * as _ from 'lodash';
|
|
|
|
import { getManualSortCompareFunction } from '../../lib/utils/helpers';
|
|
import { CapitanoCommand, Category, Document, OclifCommand } from './doc-types';
|
|
import * as utils from './utils';
|
|
|
|
function renderCapitanoCommand(command: CapitanoCommand): string[] {
|
|
const result = [`## ${ent.encode(command.signature)}`, command.help];
|
|
|
|
if (!_.isEmpty(command.options)) {
|
|
result.push('### Options');
|
|
|
|
for (const option of command.options!) {
|
|
result.push(
|
|
`#### ${utils.parseCapitanoOption(option)}`,
|
|
option.description,
|
|
);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function renderOclifCommand(command: OclifCommand): string[] {
|
|
const result = [`## ${ent.encode(command.usage)}`];
|
|
const description = (command.description || '')
|
|
.split('\n')
|
|
.slice(1) // remove the first line, which oclif uses as help header
|
|
.join('\n')
|
|
.trim();
|
|
result.push(description);
|
|
|
|
if (!_.isEmpty(command.examples)) {
|
|
result.push('Examples:', command.examples!.map(v => `\t${v}`).join('\n'));
|
|
}
|
|
|
|
if (!_.isEmpty(command.args)) {
|
|
result.push('### Arguments');
|
|
for (const arg of command.args!) {
|
|
result.push(`#### ${arg.name.toUpperCase()}`, arg.description || '');
|
|
}
|
|
}
|
|
|
|
if (!_.isEmpty(command.flags)) {
|
|
result.push('### Options');
|
|
for (const [name, flag] of Object.entries(command.flags!)) {
|
|
if (name === 'help') {
|
|
continue;
|
|
}
|
|
flag.name = name;
|
|
const flagUsage = flagUsages([flag])
|
|
.map(([usage, _description]) => usage)
|
|
.join()
|
|
.trim();
|
|
result.push(`#### ${flagUsage}`);
|
|
result.push(flag.description || '');
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function renderCategory(category: Category): string[] {
|
|
const result = [`# ${category.title}`];
|
|
for (const command of category.commands) {
|
|
result.push(
|
|
...(typeof command === 'object'
|
|
? renderCapitanoCommand(command)
|
|
: renderOclifCommand(command)),
|
|
);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function getAnchor(cmdSignature: string): string {
|
|
return `#${_.trim(cmdSignature.replace(/\W+/g, '-'), '-').toLowerCase()}`;
|
|
}
|
|
|
|
function renderToc(categories: Category[]): string[] {
|
|
const result = [`# CLI Command Reference`];
|
|
|
|
for (const category of categories) {
|
|
result.push(`- ${category.title}`);
|
|
result.push(
|
|
category.commands
|
|
.map(command => {
|
|
const signature =
|
|
typeof command === 'object'
|
|
? command.signature // Capitano
|
|
: utils.capitanoizeOclifUsage(command.usage); // oclif
|
|
return `\t- [${ent.encode(signature)}](${getAnchor(signature)})`;
|
|
})
|
|
.join('\n'),
|
|
);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
const manualCategorySorting: { [category: string]: string[] } = {
|
|
'Environment Variables': ['envs', 'env rm', 'env add', 'env rename'],
|
|
};
|
|
|
|
function sortCommands(doc: Document): void {
|
|
for (const category of doc.categories) {
|
|
if (category.title in manualCategorySorting) {
|
|
category.commands = category.commands.sort(
|
|
getManualSortCompareFunction<CapitanoCommand | OclifCommand, string>(
|
|
manualCategorySorting[category.title],
|
|
(cmd: CapitanoCommand | OclifCommand, x: string) =>
|
|
typeof cmd === 'object' // Capitano vs oclif command
|
|
? cmd.signature.replace(/\W+/g, ' ').includes(x)
|
|
: (cmd.usage || '')
|
|
.toString()
|
|
.replace(/\W+/g, ' ')
|
|
.includes(x),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
export function render(doc: Document) {
|
|
sortCommands(doc);
|
|
const result = [
|
|
`# ${doc.title}`,
|
|
doc.introduction,
|
|
...renderToc(doc.categories),
|
|
];
|
|
for (const category of doc.categories) {
|
|
result.push(...renderCategory(category));
|
|
}
|
|
return result.join('\n\n');
|
|
}
|