feat(cli): list commands (#4245)

* add listCommands to cli/run

* add listCommands to cli/run (2)

* lint

* lint

* lint

* fix

* fixes

* fix

* lint

* maxCharsPerLine = process.stdout.columns * 80 / 100

* fix test

* fix imports

* refactor foldLines()

* default process.stdout.columns to 80

* default to 80

* fix

* fix test

* lint

* fix test

* add help flags to main usage

* fix

* fix

* fix
This commit is contained in:
Jonas Galvez 2018-11-01 00:53:06 -03:00 committed by Sébastien Chopin
parent 1dd32d0d21
commit 6dadadfa25
7 changed files with 75 additions and 42 deletions

View File

@ -1,12 +1,9 @@
import parseArgs from 'minimist'
import { name, version } from '../package.json'
import { loadNuxtConfig, indent, foldLines } from './utils'
import { loadNuxtConfig } from './utils'
import { indent, foldLines, startSpaces, optionSpaces } from './formatting'
import * as imports from './imports'
const startSpaces = 2
const optionSpaces = 2
const maxCharsPerLine = 80
export default class NuxtCommand {
constructor({ name, description, usage, options, run } = {}) {
this.name = name || ''
@ -117,15 +114,14 @@ export default class NuxtCommand {
const i = indent(maxOptionLength + optionSpaces - option.length)
return foldLines(
option + i + description,
maxCharsPerLine,
startSpaces + maxOptionLength + optionSpaces * 2,
startSpaces + optionSpaces
)
}).join('\n')
const usage = foldLines(`Usage: nuxt ${this.usage} [options]`, maxCharsPerLine, startSpaces)
const description = foldLines(this.description, maxCharsPerLine, startSpaces)
const opts = foldLines(`Options:`, maxCharsPerLine, startSpaces) + '\n\n' + _opts
const usage = foldLines(`Usage: nuxt ${this.usage} [options]`, startSpaces)
const description = foldLines(this.description, startSpaces)
const opts = foldLines(`Options:`, startSpaces) + '\n\n' + _opts
return `${usage}\n\n${description}\n\n${opts}\n\n`
}

View File

@ -0,0 +1,29 @@
import wrapAnsi from 'wrap-ansi'
export const startSpaces = 2
export const optionSpaces = 2
// 80% of terminal column width
export const maxCharsPerLine = (process.stdout.columns || 100) * 80 / 100
export function indent(count, chr = ' ') {
return chr.repeat(count)
}
export function indentLines(string, spaces, firstLineSpaces) {
const lines = Array.isArray(string) ? string : string.split('\n')
let s = ''
if (lines.length) {
const i0 = indent(firstLineSpaces === undefined ? spaces : firstLineSpaces)
s = i0 + lines.shift()
}
if (lines.length) {
const i = indent(spaces)
s += '\n' + lines.map(l => i + l).join('\n')
}
return s
}
export function foldLines(string, spaces, firstLineSpaces, maxCharsPerLine) {
return indentLines(wrapAnsi(string, maxCharsPerLine, { trim: false }), spaces, firstLineSpaces)
}

View File

@ -2,6 +2,34 @@ import consola from 'consola'
import NuxtCommand from './command'
import * as commands from './commands'
import setup from './setup'
import { indent, foldLines, startSpaces, optionSpaces } from './formatting'
async function listCommands(_commands) {
_commands = await Promise.all(
Object.keys(_commands).map((cmd) => {
return _commands[cmd]().then(m => m.default)
})
)
let maxLength = 0
const commandsHelp = []
for (const name in _commands) {
commandsHelp.push([_commands[name].usage, _commands[name].description])
maxLength = Math.max(maxLength, _commands[name].usage.length)
}
const _cmmds = commandsHelp.map(([cmd, description]) => {
const i = indent(maxLength + optionSpaces - cmd.length)
return foldLines(
cmd + i + description,
startSpaces + maxLength + optionSpaces * 2,
startSpaces + optionSpaces
)
}).join('\n')
const usage = foldLines(`Usage: nuxt <command> [--help|-h]`, startSpaces)
const cmmds = foldLines(`Commands:`, startSpaces) + '\n\n' + _cmmds
process.stdout.write(`${usage}\n\n${cmmds}\n\n`)
}
export default function run() {
const defaultCommand = 'dev'
@ -18,6 +46,10 @@ export default function run() {
if (cmds.has(cmd)) {
process.argv.splice(2, 1)
} else {
if (process.argv.includes('--help') || process.argv.includes('-h')) {
listCommands({ ...commands }).then(() => process.exit(0))
return
}
cmd = defaultCommand
}

View File

@ -2,7 +2,6 @@ import path from 'path'
import { existsSync } from 'fs'
import consola from 'consola'
import esm from 'esm'
import wrapAnsi from 'wrap-ansi'
import defaultsDeep from 'lodash/defaultsDeep'
import { getDefaultNuxtConfig } from '@nuxt/config'
@ -62,25 +61,3 @@ export async function loadNuxtConfig(argv) {
return options
}
export function indent(count, chr = ' ') {
return chr.repeat(count)
}
export function indentLines(string, spaces, firstLineSpaces) {
const lines = Array.isArray(string) ? string : string.split('\n')
let s = ''
if (lines.length) {
const i0 = indent(firstLineSpaces === undefined ? spaces : firstLineSpaces)
s = i0 + lines.shift().trim()
}
if (lines.length) {
const i = indent(spaces)
s += '\n' + lines.map(l => i + l.trim()).join('\n')
}
return s
}
export function foldLines(string, maxCharsPerLine, spaces, firstLineSpaces) {
return indentLines(wrapAnsi(string, maxCharsPerLine, { trim: false }), spaces, firstLineSpaces)
}

View File

@ -3,8 +3,7 @@
exports[`cli/command builds help text 1`] = `
" Usage: nuxt this is how you do it [options]
a very long description that is longer than 80 chars and should wrap to the next
line while keeping indentation
a very long description that should not wrap to the next line because is not longer than the terminal width
Options:
@ -16,8 +15,7 @@ exports[`cli/command builds help text 1`] = `
--port, -p Port number on which to start the application
--hostname, -H Hostname on which to start the application
--unix-socket, -n Path to a UNIX socket
--foo very long option that is longer than 80 chars and should wrap
to the next line while keeping indentation
--foo very long option that is not longer than the terminal width and should not wrap to the next line
"
`;

View File

@ -101,15 +101,15 @@ describe('cli/command', () => {
test('builds help text', () => {
const cmd = new Command({
description: 'a very long description that is longer than 80 chars and ' +
'should wrap to the next line while keeping indentation',
description: 'a very long description that should not wrap to the next line because is not longer ' +
'than the terminal width',
usage: 'this is how you do it',
options: {
...allOptions,
foo: {
type: 'boolean',
description: 'very long option that is longer than 80 chars and ' +
'should wrap to the next line while keeping indentation'
description: 'very long option that is not longer than the terminal width and ' +
'should not wrap to the next line'
}
}
})

View File

@ -1,6 +1,7 @@
import { getDefaultNuxtConfig } from '@nuxt/config'
import { consola } from '../utils'
import * as utils from '../../src/utils'
import * as fmt from '../../src/formatting'
describe('cli/utils', () => {
afterEach(() => jest.resetAllMocks())
@ -96,10 +97,10 @@ describe('cli/utils', () => {
})
test('indent', () => {
expect(utils.indent(4)).toBe(' ')
expect(fmt.indent(4)).toBe(' ')
})
test('indent custom char', () => {
expect(utils.indent(4, '-')).toBe('----')
expect(fmt.indent(4, '-')).toBe('----')
})
})