Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions src/commands/base-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,11 @@ export default class BaseCommand extends Command {
}

#noBaseOptions = false

get noBaseOptions(): boolean {
return this.#noBaseOptions
}

/** don't show help options on command overview (mostly used on top commands like `addons` where options only apply on children) */
noHelpOptions() {
this.#noBaseOptions = true
Expand Down Expand Up @@ -353,7 +358,6 @@ export default class BaseCommand extends Command {

/** override the longestOptionTermLength to react on hide options flag */
help.longestOptionTermLength = (command: BaseCommand, helper: Help): number =>
// @ts-expect-error TS(2551) FIXME: Property 'noBaseOptions' does not exist on type 'C... Remove this comment to see the full error message
(command.noBaseOptions === false &&
helper.visibleOptions(command).reduce((max, option) => Math.max(max, helper.optionTerm(option).length), 0)) ||
0
Expand All @@ -367,9 +371,9 @@ export default class BaseCommand extends Command {
const bang = isCommand ? `${HELP_$} ` : ''

if (description) {
const pad = termWidth + HELP_SEPARATOR_WIDTH
const fullText = `${bang}${term.padEnd(pad - (isCommand ? 2 : 0))}${chalk.grey(description)}`
return helper.wrap(fullText, helpWidth - HELP_INDENT_WIDTH, pad)
const pad = Math.max(termWidth + HELP_SEPARATOR_WIDTH - (isCommand ? 2 : 0), term.length + 2)
const fullText = `${bang}${term.padEnd(pad)}${chalk.grey(description)}`
return helper.wrap(fullText, helpWidth - HELP_INDENT_WIDTH, pad + (isCommand ? 2 : 0))
}

return `${bang}${term}`
Expand Down
65 changes: 65 additions & 0 deletions tests/unit/commands/help-format.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { describe, expect, test } from 'vitest'

import BaseCommand from '../../../src/commands/base-command.js'

// eslint-disable-next-line no-control-regex
const stripAnsi = (text: string): string => text.replace(/\[[0-9;]*m/g, '')

describe('help formatting without a TTY', () => {
test('separates a short flag from its description with at least two spaces', () => {
const program = new BaseCommand('netlify')
const build = program
.command('build')
.description('Build on your local machine')
.option('--dry', 'Dry run: show instructions without running them', false)
.option('--context <context>', 'Specify a deploy context')

const helpText = stripAnsi(build.helpInformation())

expect(helpText).toMatch(/--dry {2,}Dry run: show instructions/)
expect(helpText).not.toMatch(/--dryDry/)
})

test('every OPTIONS row keeps at least two spaces between term and description', () => {
const program = new BaseCommand('netlify')
const api = program
.command('api')
.description('Run any Netlify API method')
.option('-d, --data <data>', 'Data to use')
.option('--list', 'List out available API methods', false)

const helpText = stripAnsi(api.helpInformation())
const optionsSection = helpText.split('OPTIONS')[1]?.split('\n\n')[0] ?? ''
const rows = optionsSection.split('\n').filter((line) => /^\s+-/.test(line))

expect(rows.length).toBeGreaterThan(0)
for (const row of rows) {
expect(row).toMatch(/^ {2}\S.* {2,}\S/)
}

expect(helpText).not.toMatch(/<data>Data/)
})

test('option terms contribute to the help column width', () => {
const program = new BaseCommand('netlify')
const cmd = program
.command('example')
.description('Example command')
.option('--a-really-long-option-name <value>', 'Long option')
.option('--dry', 'Short option')

const helpText = stripAnsi(cmd.helpInformation())
const longRow = helpText.split('\n').find((line) => line.includes('--a-really-long-option-name'))

expect(longRow).toBeDefined()
expect(longRow).toMatch(/ {2,}Long option/)
})

test('noHelpOptions exposes noBaseOptions and hides the OPTIONS section', () => {
const program = new BaseCommand('netlify')

expect(program.noBaseOptions).toBe(false)
program.noHelpOptions()
expect(program.noBaseOptions).toBe(true)
})
})
Loading