feat: allow unknown options if they are prefixed with "config."

PR #2755
close #2685
close #2710
This commit is contained in:
Zoltan Kochan
2020-08-07 22:31:38 +03:00
committed by GitHub
parent e974b7f22e
commit be0a3db9ba
5 changed files with 47 additions and 5 deletions

View File

@@ -0,0 +1,5 @@
---
"@pnpm/parse-cli-args": minor
---
Allow unknown options that are prefixed with "config."

View File

@@ -126,17 +126,32 @@ export default async function parseCliArgs (
}
const knownOptions = new Set(Object.keys(types))
const unknownOptions = getUnknownOptions(Object.keys(options), knownOptions)
return {
argv,
cmd,
options,
params,
unknownOptions,
workspaceDir,
...normalizeOptions(options, knownOptions),
}
}
const CUSTOM_OPTION_PREFIX = 'config.'
function normalizeOptions (options: Record<string, unknown>, knownOptions: Set<string>) {
const standardOptionNames = []
const normalizedOptions = {}
for (const [optionName, optionValue] of Object.entries(options)) {
if (optionName.startsWith(CUSTOM_OPTION_PREFIX)) {
normalizedOptions[optionName.substring(CUSTOM_OPTION_PREFIX.length)] = optionValue
continue
}
normalizedOptions[optionName] = optionValue
standardOptionNames.push(optionName)
}
const unknownOptions = getUnknownOptions(standardOptionNames, knownOptions)
return { options: normalizedOptions, unknownOptions }
}
function getUnknownOptions (usedOptions: string[], knownOptions: Set<string>) {
const unknownOptions = new Map<string, string[]>()
const closestMatches = getClosestOptionMatches.bind(null, Array.from(knownOptions))

View File

@@ -113,6 +113,27 @@ test('detect unknown options', async (t) => {
t.end()
})
test('allow any option that starts with "config."', async (t) => {
const { options, unknownOptions } = await parseCliArgs({
...DEFAULT_OPTS,
getTypesByCommandName: (commandName: string) => {
if (commandName === 'install') {
return {
bar: Boolean,
recursive: Boolean,
registry: String,
}
}
return {}
},
universalOptionsTypes: { filter: [String, Array] },
}, ['install', '--config.save-dev', '--registry=https://example.com', '--config.qar', '--filter=packages'])
t.deepEqual(Array.from(unknownOptions.entries()), [])
t.equal(options.qar, true)
t.equal(options['save-dev'], true)
t.end()
})
test('do not incorrectly change "install" command to "add"', async (t) => {
const { cmd } = await parseCliArgs({
...DEFAULT_OPTS,

View File

@@ -12,5 +12,6 @@ export function formatUnknownOptionsError (unknownOptions: Map<string, string[]>
if (!didYouMeanOptions?.length) {
return output
}
return `${output}\nDid you mean '${didYouMeanOptions.join("', or '")}'?`
return `${output}
Did you mean '${didYouMeanOptions.join("', or '")}'? Use "--config.unknown=value" to force an unknown option.`
}

View File

@@ -12,7 +12,7 @@ test('formatUnknownOptionsError()', async (t) => {
t.equal(
formatUnknownOptionsError(new Map([['foo', ['foa', 'fob']]])),
`${ERROR} ${chalk.red("Unknown option: 'foo'")}
Did you mean 'foa', or 'fob'?`
Did you mean 'foa', or 'fob'? Use "--config.unknown=value" to force an unknown option.`
)
t.equal(
formatUnknownOptionsError(new Map([['foo', []], ['bar', []]])),