mirror of
https://github.com/nuxt/nuxt.git
synced 2025-02-07 09:22:27 +00:00
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:
parent
1dd32d0d21
commit
6dadadfa25
@ -1,12 +1,9 @@
|
|||||||
import parseArgs from 'minimist'
|
import parseArgs from 'minimist'
|
||||||
import { name, version } from '../package.json'
|
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'
|
import * as imports from './imports'
|
||||||
|
|
||||||
const startSpaces = 2
|
|
||||||
const optionSpaces = 2
|
|
||||||
const maxCharsPerLine = 80
|
|
||||||
|
|
||||||
export default class NuxtCommand {
|
export default class NuxtCommand {
|
||||||
constructor({ name, description, usage, options, run } = {}) {
|
constructor({ name, description, usage, options, run } = {}) {
|
||||||
this.name = name || ''
|
this.name = name || ''
|
||||||
@ -117,15 +114,14 @@ export default class NuxtCommand {
|
|||||||
const i = indent(maxOptionLength + optionSpaces - option.length)
|
const i = indent(maxOptionLength + optionSpaces - option.length)
|
||||||
return foldLines(
|
return foldLines(
|
||||||
option + i + description,
|
option + i + description,
|
||||||
maxCharsPerLine,
|
|
||||||
startSpaces + maxOptionLength + optionSpaces * 2,
|
startSpaces + maxOptionLength + optionSpaces * 2,
|
||||||
startSpaces + optionSpaces
|
startSpaces + optionSpaces
|
||||||
)
|
)
|
||||||
}).join('\n')
|
}).join('\n')
|
||||||
|
|
||||||
const usage = foldLines(`Usage: nuxt ${this.usage} [options]`, maxCharsPerLine, startSpaces)
|
const usage = foldLines(`Usage: nuxt ${this.usage} [options]`, startSpaces)
|
||||||
const description = foldLines(this.description, maxCharsPerLine, startSpaces)
|
const description = foldLines(this.description, startSpaces)
|
||||||
const opts = foldLines(`Options:`, maxCharsPerLine, startSpaces) + '\n\n' + _opts
|
const opts = foldLines(`Options:`, startSpaces) + '\n\n' + _opts
|
||||||
|
|
||||||
return `${usage}\n\n${description}\n\n${opts}\n\n`
|
return `${usage}\n\n${description}\n\n${opts}\n\n`
|
||||||
}
|
}
|
||||||
|
29
packages/cli/src/formatting.js
Normal file
29
packages/cli/src/formatting.js
Normal 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)
|
||||||
|
}
|
@ -2,6 +2,34 @@ import consola from 'consola'
|
|||||||
import NuxtCommand from './command'
|
import NuxtCommand from './command'
|
||||||
import * as commands from './commands'
|
import * as commands from './commands'
|
||||||
import setup from './setup'
|
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() {
|
export default function run() {
|
||||||
const defaultCommand = 'dev'
|
const defaultCommand = 'dev'
|
||||||
@ -18,6 +46,10 @@ export default function run() {
|
|||||||
if (cmds.has(cmd)) {
|
if (cmds.has(cmd)) {
|
||||||
process.argv.splice(2, 1)
|
process.argv.splice(2, 1)
|
||||||
} else {
|
} else {
|
||||||
|
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
||||||
|
listCommands({ ...commands }).then(() => process.exit(0))
|
||||||
|
return
|
||||||
|
}
|
||||||
cmd = defaultCommand
|
cmd = defaultCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ import path from 'path'
|
|||||||
import { existsSync } from 'fs'
|
import { existsSync } from 'fs'
|
||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
import esm from 'esm'
|
import esm from 'esm'
|
||||||
import wrapAnsi from 'wrap-ansi'
|
|
||||||
import defaultsDeep from 'lodash/defaultsDeep'
|
import defaultsDeep from 'lodash/defaultsDeep'
|
||||||
import { getDefaultNuxtConfig } from '@nuxt/config'
|
import { getDefaultNuxtConfig } from '@nuxt/config'
|
||||||
|
|
||||||
@ -62,25 +61,3 @@ export async function loadNuxtConfig(argv) {
|
|||||||
|
|
||||||
return options
|
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)
|
|
||||||
}
|
|
||||||
|
@ -3,8 +3,7 @@
|
|||||||
exports[`cli/command builds help text 1`] = `
|
exports[`cli/command builds help text 1`] = `
|
||||||
" Usage: nuxt this is how you do it [options]
|
" 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
|
a very long description that should not wrap to the next line because is not longer than the terminal width
|
||||||
line while keeping indentation
|
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
|
|
||||||
@ -16,8 +15,7 @@ exports[`cli/command builds help text 1`] = `
|
|||||||
--port, -p Port number on which to start the application
|
--port, -p Port number on which to start the application
|
||||||
--hostname, -H Hostname on which to start the application
|
--hostname, -H Hostname on which to start the application
|
||||||
--unix-socket, -n Path to a UNIX socket
|
--unix-socket, -n Path to a UNIX socket
|
||||||
--foo very long option that is longer than 80 chars and should wrap
|
--foo very long option that is not longer than the terminal width and should not wrap to the next line
|
||||||
to the next line while keeping indentation
|
|
||||||
|
|
||||||
"
|
"
|
||||||
`;
|
`;
|
||||||
|
@ -101,15 +101,15 @@ describe('cli/command', () => {
|
|||||||
|
|
||||||
test('builds help text', () => {
|
test('builds help text', () => {
|
||||||
const cmd = new Command({
|
const cmd = new Command({
|
||||||
description: 'a very long description that is longer than 80 chars and ' +
|
description: 'a very long description that should not wrap to the next line because is not longer ' +
|
||||||
'should wrap to the next line while keeping indentation',
|
'than the terminal width',
|
||||||
usage: 'this is how you do it',
|
usage: 'this is how you do it',
|
||||||
options: {
|
options: {
|
||||||
...allOptions,
|
...allOptions,
|
||||||
foo: {
|
foo: {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
description: 'very long option that is longer than 80 chars and ' +
|
description: 'very long option that is not longer than the terminal width and ' +
|
||||||
'should wrap to the next line while keeping indentation'
|
'should not wrap to the next line'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { getDefaultNuxtConfig } from '@nuxt/config'
|
import { getDefaultNuxtConfig } from '@nuxt/config'
|
||||||
import { consola } from '../utils'
|
import { consola } from '../utils'
|
||||||
import * as utils from '../../src/utils'
|
import * as utils from '../../src/utils'
|
||||||
|
import * as fmt from '../../src/formatting'
|
||||||
|
|
||||||
describe('cli/utils', () => {
|
describe('cli/utils', () => {
|
||||||
afterEach(() => jest.resetAllMocks())
|
afterEach(() => jest.resetAllMocks())
|
||||||
@ -96,10 +97,10 @@ describe('cli/utils', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
test('indent', () => {
|
test('indent', () => {
|
||||||
expect(utils.indent(4)).toBe(' ')
|
expect(fmt.indent(4)).toBe(' ')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('indent custom char', () => {
|
test('indent custom char', () => {
|
||||||
expect(utils.indent(4, '-')).toBe('----')
|
expect(fmt.indent(4, '-')).toBe('----')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user