mirror of
https://github.com/chenasraf/massarg.git
synced 2026-05-18 01:39:05 +00:00
fix: move negation logic to MassargFlag
This commit is contained in:
@@ -41,6 +41,9 @@ export type CommandConfig<RunArgs extends ArgsObject = ArgsObject> = z.infer<
|
|||||||
ReturnType<typeof CommandConfig<RunArgs>>
|
ReturnType<typeof CommandConfig<RunArgs>>
|
||||||
>
|
>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object with string keys and any values.
|
||||||
|
*/
|
||||||
export type ArgsObject = Record<string | number | symbol, any>
|
export type ArgsObject = Record<string | number | symbol, any>
|
||||||
|
|
||||||
export type Runner<Args extends ArgsObject> = (
|
export type Runner<Args extends ArgsObject> = (
|
||||||
@@ -168,9 +171,10 @@ export class MassargCommand<Args extends ArgsObject = ArgsObject>
|
|||||||
* a boolean value, or to indicate that a command should be run in a different
|
* a boolean value, or to indicate that a command should be run in a different
|
||||||
* mode.
|
* mode.
|
||||||
*
|
*
|
||||||
* A flag can be negated by prefixing it with `no-`. For example, `--no-verbose`,
|
* A flag can be negated by using `negatable: true`. By default, the negated name is the same
|
||||||
* or by prefixing the alias with `^` instead of `-`. This is configurable via the command's
|
* as the option name, prefixed by `no-`, and each of the aliases will be uppercased.
|
||||||
* configuration.
|
* For example, `--verbose` and `--no-verbose`, or `-v` and `-V`.
|
||||||
|
* This behavior can be overridden by the `negatedName` and `negatedAliases` options.
|
||||||
*/
|
*/
|
||||||
flag(config: FlagConfig): MassargCommand<Args>
|
flag(config: FlagConfig): MassargCommand<Args>
|
||||||
flag(config: MassargFlag): MassargCommand<Args>
|
flag(config: MassargFlag): MassargCommand<Args>
|
||||||
|
|||||||
@@ -9,22 +9,12 @@ export const OptionConfig = <OptionType, Args extends ArgsObject = ArgsObject>(
|
|||||||
z.object({
|
z.object({
|
||||||
/** Name of the option */
|
/** Name of the option */
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
/**
|
|
||||||
* Negation name of the option, which can be used with the full option notation, e.g. `loud` for `--loud`.
|
|
||||||
* Defaults to `no-{name}`, e.g. `--no-quiet`.
|
|
||||||
*/
|
|
||||||
negationName: z.string().optional(),
|
|
||||||
/** Description of the option, displayed in the help output */
|
/** Description of the option, displayed in the help output */
|
||||||
description: z.string(),
|
description: z.string(),
|
||||||
/** Default value of the option */
|
/** Default value of the option */
|
||||||
defaultValue: z.any().optional(),
|
defaultValue: z.any().optional(),
|
||||||
/** Aliases for the option, which can be used with the shorthand option notation. */
|
/** Aliases for the option, which can be used with the shorthand option notation. */
|
||||||
aliases: z.string().array(),
|
aliases: z.string().array(),
|
||||||
/**
|
|
||||||
* Negation aliases for the option, which can be used with the shorthand option notation, e.g. `Q` for `-Q`.
|
|
||||||
* Defaults to uppercase of each of the aliases provided.
|
|
||||||
*/
|
|
||||||
negationAliases: z.string().array().optional(),
|
|
||||||
/**
|
/**
|
||||||
* Parse the value of the option. You can return any type here, or throw an error if the value
|
* Parse the value of the option. You can return any type here, or throw an error if the value
|
||||||
* is invalid.
|
* is invalid.
|
||||||
@@ -66,10 +56,29 @@ export const FlagConfig = OptionConfig<boolean>(z.any())
|
|||||||
z.object({
|
z.object({
|
||||||
/** Whether the flag can be negated, e.g. `--no-verbose` */
|
/** Whether the flag can be negated, e.g. `--no-verbose` */
|
||||||
negatable: z.boolean().optional(),
|
negatable: z.boolean().optional(),
|
||||||
|
/**
|
||||||
|
* Negation name of the option, which can be used with the full option notation.
|
||||||
|
*
|
||||||
|
* Defaults to `no-{name}` of your option's name, e.g. `verbose` becomes `--no-verbose`.
|
||||||
|
*
|
||||||
|
* To use this, you must set `negatable: true` in the option's configuration.
|
||||||
|
*/
|
||||||
|
negationName: z.string().optional(),
|
||||||
|
/**
|
||||||
|
* Negation aliases for the option, which can be used with the shorthand option notation.
|
||||||
|
*
|
||||||
|
* Defaults to uppercase of each of the aliases provided, e.g. `q` becomes `-Q`.
|
||||||
|
*
|
||||||
|
* To use this, you must set `negatable: true` in the option's configuration.
|
||||||
|
*/
|
||||||
|
negationAliases: z.string().array().optional(),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
export type FlagConfig = z.infer<typeof FlagConfig>
|
export type FlagConfig = z.infer<typeof FlagConfig>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function that parses an option value.
|
||||||
|
*/
|
||||||
export type Parser<Args extends ArgsObject = ArgsObject, OptionType extends any = any> = (
|
export type Parser<Args extends ArgsObject = ArgsObject, OptionType extends any = any> = (
|
||||||
x: string,
|
x: string,
|
||||||
y: Args,
|
y: Args,
|
||||||
@@ -160,11 +169,9 @@ export class MassargOption<OptionType extends any = unknown, Args extends ArgsOb
|
|||||||
implements OptionConfig<OptionType, Args>
|
implements OptionConfig<OptionType, Args>
|
||||||
{
|
{
|
||||||
name: string
|
name: string
|
||||||
negationName: string
|
|
||||||
description: string
|
description: string
|
||||||
defaultValue?: OptionType
|
defaultValue?: OptionType
|
||||||
aliases: string[]
|
aliases: string[]
|
||||||
negationAliases: string[]
|
|
||||||
parse: Parser<Args, OptionType>
|
parse: Parser<Args, OptionType>
|
||||||
isArray: boolean
|
isArray: boolean
|
||||||
isRequired: boolean
|
isRequired: boolean
|
||||||
@@ -174,11 +181,9 @@ export class MassargOption<OptionType extends any = unknown, Args extends ArgsOb
|
|||||||
constructor(options: OptionConfig<OptionType, Args>) {
|
constructor(options: OptionConfig<OptionType, Args>) {
|
||||||
OptionConfig(z.any()).parse(options)
|
OptionConfig(z.any()).parse(options)
|
||||||
this.name = options.name
|
this.name = options.name
|
||||||
this.negationName = options.negationName ?? `no-${options.name}`
|
|
||||||
this.description = options.description
|
this.description = options.description
|
||||||
this.defaultValue = options.defaultValue
|
this.defaultValue = options.defaultValue
|
||||||
this.aliases = options.aliases
|
this.aliases = options.aliases
|
||||||
this.negationAliases = options.negationAliases ?? this.aliases.map((a) => a.toUpperCase())
|
|
||||||
this.parse = options.parse ?? ((x: string) => x as OptionType)
|
this.parse = options.parse ?? ((x: string) => x as OptionType)
|
||||||
this.isArray = options.array ?? false
|
this.isArray = options.array ?? false
|
||||||
this.isDefault = options.isDefault ?? false
|
this.isDefault = options.isDefault ?? false
|
||||||
@@ -248,27 +253,10 @@ export class MassargOption<OptionType extends any = unknown, Args extends ArgsOb
|
|||||||
return {
|
return {
|
||||||
name: prefixes.normalPrefix + this.name,
|
name: prefixes.normalPrefix + this.name,
|
||||||
aliases: this.aliases.map((a) => prefixes.aliasPrefix + a),
|
aliases: this.aliases.map((a) => prefixes.aliasPrefix + a),
|
||||||
negationName: prefixes.normalPrefix + this.negationName,
|
negationName: '',
|
||||||
negationAliases: this.negationAliases.map((a) => prefixes.aliasPrefix + a),
|
negationAliases: [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the name of the flag, removing any prefixes. It is discriminate of if the option
|
|
||||||
* exists, as it is a static method; it only returns the name of the flag if it matches the
|
|
||||||
* prefixes format.
|
|
||||||
*/
|
|
||||||
// static findNameInArg(arg: string, prefixes: Prefixes): string {
|
|
||||||
// const { normalPrefix: optionPrefix, aliasPrefix } = prefixes
|
|
||||||
// if (arg.startsWith(optionPrefix)) {
|
|
||||||
// return arg.slice(optionPrefix.length)
|
|
||||||
// }
|
|
||||||
// // short prefix
|
|
||||||
// if (arg.startsWith(aliasPrefix)) {
|
|
||||||
// return arg.slice(aliasPrefix.length)
|
|
||||||
// }
|
|
||||||
// return '<blank>'
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -328,9 +316,10 @@ export class MassargNumber extends MassargOption<number> {
|
|||||||
* a boolean value, or to indicate that a command should be run in a different
|
* a boolean value, or to indicate that a command should be run in a different
|
||||||
* mode.
|
* mode.
|
||||||
*
|
*
|
||||||
* A flag can be negated by prefixing it with `no-`. For example, `--no-verbose`,
|
* A flag can be negated by using `negatable: true`. By default, the negated name is the same
|
||||||
* or by prefixing the alias with `^` instead of `-`. This is configurable via the command's
|
* as the option name, prefixed by `no-`, and each of the aliases will be uppercased.
|
||||||
* configuration. To turn this behavior on, set `negatable: true` in the flag's configuration.
|
* For example, `--verbose` and `--no-verbose`, or `-v` and `-V`.
|
||||||
|
* This behavior can be overridden by the `negatedName` and `negatedAliases` options.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* ```ts
|
* ```ts
|
||||||
@@ -344,6 +333,8 @@ export class MassargNumber extends MassargOption<number> {
|
|||||||
*/
|
*/
|
||||||
export class MassargFlag extends MassargOption<boolean> {
|
export class MassargFlag extends MassargOption<boolean> {
|
||||||
negatable: boolean
|
negatable: boolean
|
||||||
|
negationName: string
|
||||||
|
negationAliases: string[]
|
||||||
|
|
||||||
constructor(options: FlagConfig) {
|
constructor(options: FlagConfig) {
|
||||||
super({
|
super({
|
||||||
@@ -351,13 +342,17 @@ export class MassargFlag extends MassargOption<boolean> {
|
|||||||
parse: () => true as any,
|
parse: () => true as any,
|
||||||
})
|
})
|
||||||
this.negatable = options.negatable ?? false
|
this.negatable = options.negatable ?? false
|
||||||
|
this.negationName = options.negationName ?? `no-${options.name}`
|
||||||
|
this.negationAliases = options.negationAliases ?? this.aliases.map((a) => a.toUpperCase())
|
||||||
}
|
}
|
||||||
|
|
||||||
parseDetails(argv: string[], _options: ArgsObject, prefixes: Prefixes): ArgvValue<boolean> {
|
parseDetails(argv: string[], _options: ArgsObject, prefixes: Prefixes): ArgvValue<boolean> {
|
||||||
try {
|
try {
|
||||||
const qualifiedNames = this.qualifiedNames(prefixes)
|
const qualifiedNames = this.qualifiedNames(prefixes)
|
||||||
const isNegation =
|
const isNegation =
|
||||||
argv[0] === qualifiedNames.negationName || qualifiedNames.negationAliases.includes(argv[0])
|
(qualifiedNames.negationName && argv[0] === qualifiedNames.negationName) ||
|
||||||
|
(qualifiedNames.negationAliases.length && qualifiedNames.negationAliases.includes(argv[0]))
|
||||||
|
|
||||||
if (!this.negatable && isNegation) {
|
if (!this.negatable && isNegation) {
|
||||||
throw new ParseError({
|
throw new ParseError({
|
||||||
path: [this.name],
|
path: [this.name],
|
||||||
@@ -391,6 +386,14 @@ export class MassargFlag extends MassargOption<boolean> {
|
|||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qualifiedNames(prefixes: Prefixes): QualifiedNames {
|
||||||
|
return {
|
||||||
|
...super.qualifiedNames(prefixes),
|
||||||
|
negationName: prefixes.normalPrefix + this.negationName,
|
||||||
|
negationAliases: this.negationAliases.map((a) => prefixes.aliasPrefix + a),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MassargHelpFlag extends MassargFlag {
|
export class MassargHelpFlag extends MassargFlag {
|
||||||
|
|||||||
Reference in New Issue
Block a user