Skip to main content

Named Flags

Flags are named, non-positional arguments that are passed to a command. They can be passed in any order, and depending on the type and configuration can be repeated or excluded.

Case Style

By default, Stricli will ensure that flag names are matched exactly. However, the scanner.caseStyle configuration option allows you to specify "allow-kebab-for-camel". This extends the argument scanner to allow kebab-case versions of camelCase flag names. For example, a flag that is normally passed as --allowEdits could also be passed as --allow-edits.

There is a separate configuration option documentation.caseStyle that controls which case style is used when displaying help text and documentation. By default, the documentation option will reflect the scanner option, but this can be manually overridden.

Aliases

Within Stricli, aliases refer to the alternate, single-character name of an existing flag. These only require a single - escape and can be batched together as a single argument -abc (equivalent to -a -b -c). Any single uppercase or lowercase character can be used as an alias, with the following exceptions:

  • -h (reserved for --help)
  • -H (reserved for --helpAll)
  • -v (reserved for --version when version information is provided)

Types

To be generic and flexible, Stricli supports parsing strings to any specified type. However, Stricli also provides additional support for several built-in types that have extended functionality not available to traditional parsed flags.

Parsed

The base flag type supported by Stricli is parsed. To use a parsed flag, you must provide a function that accepts a string and then returns a type that matches the associated type. Stricli provides some built-in parsers for booleans and numbers, but ultimately how you perform this parsing/validation is up to you. There are some great third party libraries like zod or typanion that are perfect for this, depending on your use case.

Enumerations

Stricli encounters all arguments as strings, and if there is an explicit set of valid string values then the enum flag type could be useful.

Given a TypeScript union of string literals (ex: "a" | "b" | "c") the parameter specification can provide a set of all values that should be supported by the flag (ex: ["a", "b", "c"]). It will then include all values in the help text, and type check a default value if provided. For auto-complete proposals, it will automatically suggest any values that match the current partial input.

Booleans (with Negation)

Instead of parsing a flag value as a raw boolean (--flag=true/false), you could instead use the special boolean flag type which has a few enhancements.

Since boolean flags can only have two values, the presence of the flag can be used to determine the value instead (--flag/-f). However, depending on the default value, it may be useful to allow for negation. The framework automatically supports additional flags prefixed with no to indicate the opposite value (--noFlag or --no-flag depending on case style). This type uses the provided looseBooleanParser under the hood to allow for values like yes/y (for true) and no/n (for false).

Counters

Stricli exposes a numberParser to support parsing input strings to numbers. However, instead of parsing the flag value as an integer (--flag=1), you could instead use the special counter flag type which has a few enhancements.

This type only applies to integers, not all numbers and is best used when counting the number of appearances of a given flag in the arguments. Each appearance of the flag increments the counter by 1.

Variants

Most flags support several different variants, some of which are enforced through type checking.

Optional

If a flag property is optional, or is otherwise possibly undefined then it must have optional: true in its configuration. This is enforced by TypeScript based on the type of the corresponding property.

Empty

It can be valuable to distinguish between --flag and --flag value. For parsed flag types, this behavior is available with the inferEmpty attribute. When this is true and the flag is encountered without an input, the input is inferred as the empty string "" instead.

/// impl.ts
export default function(flags: { override?: string }) {
console.log(flags.override);
}

/// command.ts
buildCommand({
loader: async () => import("./impl"),
parameters: {
flags: {
override: {
kind: "parsed",
parse: String,
brief: "Should override be applied, or override value",
optional: true,
inferEmpty: true,
},
},
...
},
...
});

The command configuration above will produce a command with the following behavior:

run
undefined
run --override
""
run --override foobar
"foobar"
run --help
FLAGS
--override (optional) Should override be applied, or override value

Defaults

Any flag can specify a default value as a string. For parsed flag types, this string will be parsed before being passed to the implementation. For enum flag types, this value is type checked against the list of possible values.

Variadic

A flag can be variadic when the type it represents is an array of values. In this case, the flag can be specified multiple times and each value is then parsed individually and added to a single array. If the type of a flag is an array it must be set as variadic.

Hidden

If a flag has already been marked optional, then it can also be marked as hidden. This means that the flag will not appear in the default help text, documentation, or auto-complete proposals. Hidden flags should be reserved for features that aren't necessarily user facing, but are advanced or debug-related.

The an additional system flag --helpAll (or --help-all depending on case style) will always include all flags, even hidden ones.