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
17 changes: 17 additions & 0 deletions src/autocomplete/powershell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,23 @@ Register-ArgumentCompleter -Native -CommandName ${
} else {
flaghHashtables.push(` "${f.name}" = @{ "summary" = "${flagSummary}" }`)
}

// Add flag aliases
const aliases = (f as any).aliases as string[] | undefined
if (aliases && aliases.length > 0) {
for (const alias of aliases) {
if (f.type === 'option' && f.multiple) {
flaghHashtables.push(
` "${alias}" = @{
"summary" = "${flagSummary}"
"multiple" = $true
}`,
)
} else {
flaghHashtables.push(` "${alias}" = @{ "summary" = "${flagSummary}" }`)
}
}
}
}
}

Expand Down
22 changes: 22 additions & 0 deletions src/autocomplete/zsh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,28 @@ _${this.config.bin}

flagSpec += ' \\\n'
argumentsBlock += flagSpec

// Add completions for flag aliases
const aliases = (f as any).aliases as string[] | undefined
if (aliases && aliases.length > 0) {
for (const alias of aliases) {
let aliasSpec = ''
if (f.type === 'option') {
if (f.multiple) {
aliasSpec += '"*"'
}

aliasSpec += `--${alias}"[${flagSummary}]:`
aliasSpec += f.options ? `${f.name} options:(${f.options.join(' ')})"` : 'file:_files"'
} else {
// Flag.Boolean
aliasSpec += `--${alias}"[${flagSummary}]"`
}

aliasSpec += ' \\\n'
argumentsBlock += aliasSpec
}
}
}

// add global `--help` flag
Expand Down
56 changes: 39 additions & 17 deletions src/commands/autocomplete/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,25 +262,47 @@ compinit;\n`

private genCmdPublicFlags(Command: CommandCompletion): string {
const Flags = Command.flags || {}
return Object.keys(Flags)
.filter((flag) => !Flags[flag].hidden)
.map((flag) => `--${flag}`)
.join(' ')
const flagList: string[] = []
for (const flag of Object.keys(Flags)) {
if (Flags[flag].hidden) continue
flagList.push(`--${flag}`)
// Add flag aliases
const aliases = (Flags[flag] as any).aliases as string[] | undefined
if (aliases && aliases.length > 0) {
for (const alias of aliases) {
flagList.push(`--${alias}`)
}
}
}

return flagList.join(' ')
}

private genZshFlagSpecs(Klass: any): string {
return Object.keys(Klass.flags || {})
.filter((flag) => Klass.flags && !Klass.flags[flag].hidden)
.map((flag) => {
const f = (Klass.flags && Klass.flags[flag]) || {description: ''}
const isBoolean = f.type === 'boolean'
const isOption = f.type === 'option'
const name = isBoolean ? flag : `${flag}=-`
const multiple = isOption && f.multiple ? '*' : ''
const valueCmpl = isBoolean ? '' : ':'
const completion = `${multiple}--${name}[${sanitizeDescription(f.summary || f.description)}]${valueCmpl}`
return `"${completion}"`
})
.join('\n')
const specs: string[] = []
for (const flag of Object.keys(Klass.flags || {})) {
if (Klass.flags && Klass.flags[flag].hidden) continue
const f = (Klass.flags && Klass.flags[flag]) || {description: ''}
const isBoolean = f.type === 'boolean'
const isOption = f.type === 'option'
const name = isBoolean ? flag : `${flag}=-`
const multiple = isOption && f.multiple ? '*' : ''
const valueCmpl = isBoolean ? '' : ':'
const summary = sanitizeDescription(f.summary || f.description)
const completion = `${multiple}--${name}[${summary}]${valueCmpl}`
specs.push(`"${completion}"`)

// Add flag aliases
const aliases = (f as any).aliases as string[] | undefined
if (aliases && aliases.length > 0) {
for (const alias of aliases) {
const aliasName = isBoolean ? alias : `${alias}=-`
const aliasCompletion = `${multiple}--${aliasName}[${summary}]${valueCmpl}`
specs.push(`"${aliasCompletion}"`)
}
}
}

return specs.join('\n')
}
}
91 changes: 91 additions & 0 deletions test/autocomplete/powershell.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,39 @@ const commandPluginD: Command.Loadable = {
summary: 'execute code',
}

// Command with flag aliases for testing
const commandWithFlagAliases: Command.Loadable = {
aliases: [],
args: {},
flags: {
'no-progress': {
aliases: ['noProgress'],
allowNo: false,
name: 'no-progress',
summary: 'Disable progress output.',
type: 'boolean',
},
'use-cache': {
aliases: ['useCache', 'cache'],
char: 'c',
multiple: false,
name: 'use-cache',
summary: 'Use cached data.',
type: 'option',
},
},
hidden: false,
hiddenAliases: [],
id: 'build',
async load(): Promise<Command.Class> {
return new MyCommandClass() as unknown as Command.Class
},
pluginAlias: '@My/plugine',
pluginType: 'core',
strict: false,
summary: 'Build a project',
}

const pluginA: IPlugin = {
_base: '',
alias: '@My/plugina',
Expand Down Expand Up @@ -771,4 +804,62 @@ $scriptblock = {
Register-ArgumentCompleter -Native -CommandName @("test","test1","test-cli") -ScriptBlock $scriptblock
`)
})

describe('powershell completion with flag aliases', () => {
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../package.json')
const config = new Config({root})

const pluginWithFlagAliases: IPlugin = {
_base: '',
alias: '@My/pluginWithFlagAliases',
commandIDs: ['build'],
commands: [commandWithFlagAliases],
commandsDir: '',
async findCommand(): Promise<Command.Class> {
return new MyCommandClass() as unknown as Command.Class
},
hasManifest: false,
hooks: {},
isRoot: false,
async load(): Promise<void> {},
moduleType: 'commonjs',
name: '@My/pluginWithFlagAliases',
options: {root: ''},
pjson: {} as any,
root: '',
tag: 'tag',
topics: [],
type: 'core',
valid: true,
version: '0.0.0',
}

before(async () => {
await config.load()
config.plugins.set(pluginWithFlagAliases.name, pluginWithFlagAliases)
config.plugins.delete('@oclif/plugin-autocomplete')
for (const plugin of config.getPluginsList()) {
// @ts-expect-error private method
config.loadCommands(plugin)
// @ts-expect-error private method
config.loadTopics(plugin)
}
})

it('includes flag aliases in the completion output', () => {
config.bin = 'test-cli'
config.binAliases = undefined
const powerShellComp = new PowerShellComp(config as Config)
const output = powerShellComp.generate()

// Check that main flags are present
expect(output).to.include('"no-progress" = @{ "summary" = "Disable progress output." }')
expect(output).to.include('"use-cache" = @{ "summary" = "Use cached data." }')

// Check that flag aliases are present
expect(output).to.include('"noProgress" = @{ "summary" = "Disable progress output." }')
expect(output).to.include('"useCache" = @{ "summary" = "Use cached data." }')
expect(output).to.include('"cache" = @{ "summary" = "Use cached data." }')
})
})
})
90 changes: 90 additions & 0 deletions test/autocomplete/zsh.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,39 @@ const commandPluginD: Command.Loadable = {
summary: 'execute code',
}

// Command with flag aliases for testing
const commandWithFlagAliases: Command.Loadable = {
aliases: [],
args: {},
flags: {
'no-progress': {
aliases: ['noProgress'],
allowNo: false,
name: 'no-progress',
summary: 'Disable progress output.',
type: 'boolean',
},
'use-cache': {
aliases: ['useCache', 'cache'],
char: 'c',
multiple: false,
name: 'use-cache',
summary: 'Use cached data.',
type: 'option',
},
},
hidden: false,
hiddenAliases: [],
id: 'build',
async load(): Promise<Command.Class> {
return new MyCommandClass() as unknown as Command.Class
},
pluginAlias: '@My/plugine',
pluginType: 'core',
strict: false,
summary: 'Build a project',
}

const pluginA: IPlugin = {
_base: '',
alias: '@My/plugina',
Expand Down Expand Up @@ -602,4 +635,61 @@ _test-cli
`)
})
})

describe('zsh completion with flag aliases', () => {
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../package.json')
const config = new Config({root})

const pluginWithFlagAliases: IPlugin = {
_base: '',
alias: '@My/pluginWithFlagAliases',
commandIDs: ['build'],
commands: [commandWithFlagAliases],
commandsDir: '',
async findCommand(): Promise<Command.Class> {
return new MyCommandClass() as unknown as Command.Class
},
hasManifest: false,
hooks: {},
isRoot: false,
async load(): Promise<void> {},
moduleType: 'commonjs',
name: '@My/pluginWithFlagAliases',
options: {root: ''},
pjson: {} as any,
root: '',
tag: 'tag',
topics: [],
type: 'core',
valid: true,
version: '0.0.0',
}

before(async () => {
await config.load()
config.plugins.set(pluginWithFlagAliases.name, pluginWithFlagAliases)
config.plugins.delete('@oclif/plugin-autocomplete')
for (const plugin of config.getPluginsList()) {
// @ts-expect-error private method
config.loadCommands(plugin)
// @ts-expect-error private method
config.loadTopics(plugin)
}
})

it('includes flag aliases in the completion output', () => {
config.bin = 'test-cli'
const zshCompWithSpaces = new ZshCompWithSpaces(config as Config)
const output = zshCompWithSpaces.generate()

// Check that main flags are present
expect(output).to.include('--no-progress')
expect(output).to.include('--use-cache')

// Check that flag aliases are present
expect(output).to.include('--noProgress')
expect(output).to.include('--useCache')
expect(output).to.include('--cache')
})
})
})
44 changes: 44 additions & 0 deletions test/commands/autocomplete/create.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,5 +272,49 @@ _oclif-example\n`)

/* eslint-enable no-useless-escape */
})

it('#bashCompletionFunction includes flag aliases', async () => {
const aliasConfig = new Config({root})
await aliasConfig.load()
const aliasCmd: any = new Create([], aliasConfig)
const aliasPlugin: any = new Plugin({root})
aliasCmd.config.plugins = [aliasPlugin]
aliasPlugin._manifest = () =>
readJson(
path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../test.oclif.manifest.flag-aliases.json'),
)
await aliasPlugin.load()

const bashOutput = aliasCmd.bashCompletionFunction as string
// Check that main flags are present
expect(bashOutput).to.include('--no-progress')
expect(bashOutput).to.include('--use-cache')
// Check that flag aliases are present
expect(bashOutput).to.include('--noProgress')
expect(bashOutput).to.include('--useCache')
expect(bashOutput).to.include('--cache')
})

it('#zshCompletionFunction includes flag aliases', async () => {
const aliasConfig = new Config({root})
await aliasConfig.load()
const aliasCmd: any = new Create([], aliasConfig)
const aliasPlugin: any = new Plugin({root})
aliasCmd.config.plugins = [aliasPlugin]
aliasPlugin._manifest = () =>
readJson(
path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../test.oclif.manifest.flag-aliases.json'),
)
await aliasPlugin.load()

const zshOutput = aliasCmd.zshCompletionFunction as string
// Check that main flags are present
expect(zshOutput).to.include('--no-progress')
expect(zshOutput).to.include('--use-cache')
// Check that flag aliases are present
expect(zshOutput).to.include('--noProgress')
expect(zshOutput).to.include('--useCache')
expect(zshOutput).to.include('--cache')
})
})
})
Loading