Documentation
Validator

Validator

The OptionValidator class is an internal component used by the library to register and validate option definitions. You should not need to instantiate this class directly. Instead, use the validate method on the parser instance.

Option validation

We use the term validation to refer to the "sanity check" of option definitions. It is intended for use during development, whereas in production it would impose an unnecessary performance penalty on your application. Validations behave like assertions: they assert that your program will work as expected when delivered to end-users.

To validate a set of option definitions, you must call the validate method on the parser instance. This method accepts a ValidationFlags argument with the following optional properties:

  • detectNamingIssues - whether the validation procedure should try to detect inconsistencies across option names

It returns a promise that resolves to a ValidationResult object with the following properties:

  • warning - A compilation of warning messages that represent non-impeditive issues encountered in the option definitions. You may want to print it to see if they are important to your application.

This method is asynchronous, so you must use await in order to resolve the returned promise.

Validation rules

The following sections describe the various kinds of validation performed by the validator. Unless otherwise noted, any option definition that does not satisfy one of these restrictions will raise an error with an explanatory message that may include the option's key.

Validation is performed recursively for nested commands, skipping circular references when necessary.

Names validation

Option names are subject to the restrictions listed below:

  • Option with no name - If the option is not positional (i.e., it does not accept positional arguments), then it must have at least one non-empty name.
  • Invalid option name - An option name must not contain whitespace or the equals sign '=', since this character can be used as option-parameter separator on the command-line. Any other Unicode character is allowed.
  • Duplicate option name - An option should not have duplicate names, and there cannot be two options with the same name.

In any of these restrictions, empty strings and nulls are ignored, while negation names and the positional marker are included.

Naming inconsistencies

In addition to the above, the validator may generate warnings if it detects naming inconsistencies, such as:

  • Too similar names - When two option names are very similar (e.g., if they differ by a single character in a five-character name), this may be a development mistake, or worse, it can become a source of headaches for end-users. Hence, the validator tries to find names that closely match a given name using the same algorithm used by the parser in name suggestions, just a little stricter.
  • Mixed naming convention - When a name slot contains names with different naming conventions (e.g., all-uppercase vs all-lowercase, or single-dash vs double-dash), this may be a sign of code review negligence, or worse, it can make it hard for end-users to reason about your application. Thus, the validator tries to find names within a slot that contain mixed naming patterns.

Cluster letter validation

Cluster letters are subject to the restrictions listed below:

  • Duplicate cluster letter - An option should not have duplicate cluster letters, and there cannot be two options with the same letter.
  • Invalid cluster letter - A cluster letter must not contain whitespace. Any other Unicode character is allowed.

In addition to the above, the validator may generate the following warning:

  • Variadic option with cluster letter - A variadic option that declares cluster letters must always be the last option in a cluster argument. This includes options with a fallback value, non-delimited array-valued options and function options with a variable parameter count. This might not be the intended behavior and if so, you should consider alternatives.

Constraints validation

Constraint definitions are subject to the restrictions listed below:

  • Zero enum values - In a known-valued option, if either the enumeration or the truth and falsity names are present, they must contain at least one element.
  • Duplicate enum value - In a known-valued option, if either the enumeration or the truth and falsity names are present, they must not contain duplicate elements.
  • Invalid numeric range - In a number-valued option, if the range attribute is present, then its minimum value should be strictly less than the maximum.
  • Invalid parameter count - In a function option, if the parameter count attribute is present and is a range, then its minimum value should be strictly less than the maximum, but not less than zero.

Value validation

Valued options may define a default value, and non-niladic options may define example and fallback values. If present, these attributes are subject to the same set of constraints as that of the command-line arguments, which is listed below:

  • Enums constraint violation - If the enumeration attribute is present, then the default, example and fallback values must, after being normalized, equal one of the enumerated values.
  • Regex constraint violation - In a string-valued option, if the regex attribute is present, then the default, example and fallback values must, after being normalized, match the regular expression.
  • Range constraint violation - In a number-valued option, if the range attribute is present, then the default, example and fallback values must, after being normalized, be within this range.
  • Limit constraint violation - In an array-valued option, if the limit attribute is present, then the default, example and fallback values must, after being normalized, have a length that does not exceed the given limit.

This does not apply to default callbacks. They are ignored during validation.

Requirements validation

When an option declares requirements referencing other options, these requirements are subject to the restrictions listed below:

  • Option requiring itself - An option must not declare a requirement that references itself.
  • Unknown required option - An option must not declare a requirement that references an unknown option.
  • Invalid required option - An option must not declare a requirement that references either a non-valued option (help and version) or an unknown-valued option (function and command) in a requirement.
  • Invalid required value - An option must not declare a requirement that references another option that is either always required or has a default value, if the required value is nullish (null or undefined).
  • Incompatible required value - Since a requirement can be an object with values of any kind, the data type of these values must be validated at run-time. Thus, an option must not declare a requirement that references a known-valued option, if it requires a value that does not conform to the data type expected by that option.
  • Constraint violation - If an option declares a requirement that includes a required value, then that value is subject to the same set of constraints as that of the command-line arguments, so it must satisfy the restrictions listed in value validation for the required option.

This does not apply to requirement callbacks. They are ignored during validation.

⚠️

Note that the library does not validate the satisfiability of option requirements, not only because it cannot evaluate callbacks at validation time, but also because requirement expressions can be arbitrarily complex. For example, a simple expression like req.all({opt:1}, {opt:2}) cannot be satisfied, but is hard to verify in general. This problem is known as B-SAT (opens in a new tab), which is known to be NP-complete (opens in a new tab).

Positional validation

Options declared with the positional attribute are subject to the restrictions listed below:

  • Duplicate positional option - Since positional arguments have no name, they must pertain to exactly one option. Hence, there cannot be two options with the positional attribute in the same set of option definitions.
  • Empty positional marker - If an option defines a positional marker, it cannot be the empty string.

Version validation

A version option is very simple and has only one restraint:

  • Empty version string - A version option must not contain an empty version string.

Validator configuration

Both the validation and parsing methods may throw errors which can be customized with a ValidatorConfig object. This object has some optional properties, as described below.

Error styles

The styles property specifies the styles of text elements in both error and help messages, and has the following optional properties:

  • boolean - the style of boolean values (defaults to fg.yellow)
  • string - the style of string values (defaults to fg.green)
  • number - the style of number values (defaults to fg.yellow)
  • regex - the style of regular expressions (defaults to fg.red)
  • option - the style of option names (defaults to fg.brightMagenta)
  • value - the style of unknown values (defaults to fg.brightBlack)
  • url - the style of URLs (defaults to fg.brightBlack)
  • text - the style of general text (defaults to tf.clear)
💡

You can also set these styles to the empty string, if you want to disable text styling for your application.

Error items

The ErrorItem enumeration lists the kinds of error messages that may be raised by the library. They are listed in the next sub-sections.

Parsing errors

  • unknownOption - when an option name is not found, with possible name suggestions
  • unsatisfiedRequirement - when an option requirement is not satisfied
  • missingRequiredOption - when an option that is always required was not specified
  • missingParameter - when an option parameter is expected but was not specified
  • missingPackageJson - when it fails to find a "package.json" file when resolving the version
  • disallowedInlineParameter - when either a niladic option or a positional marker is specified with an inline parameter
  • unsatisfiedCondRequirement - when an option's conditional requirement is not satisfied
  • invalidClusterOption - when either a variadic option or a command option is specified in the middle of a cluster argument
  • missingInlineParameter - when an option is specified without an inline parameter, despite it being required

Validation errors

  • emptyPositionalMarker - when a positional option has an empty positional marker
  • unnamedOption - when a non-positional option has no name
  • invalidOptionName - when an option has an invalid name
  • invalidVersionDefinition - when a version option has an empty version string
  • invalidSelfRequirement - when an option references itself in a requirement
  • unknownRequiredOption - when an option references an unknown option in a requirement
  • invalidRequiredOption - when an option references either a non-valued or an unknown-valued option in a requirement
  • invalidRequiredValue - when an option uses a nullish value in a requirement referencing an option that is either always required or has a default value
  • incompatibleRequiredValue - when an option is required with a value of incompatible data type
  • emptyEnumsDefinition - either an enumeration constraint or the truth and falsity names have zero length
  • duplicateOptionName - when there are two identical option names
  • duplicatePositionalOption - when there are two or more positional options
  • duplicateEnumValue - when either an enumeration constraint or the truth and falsity names have duplicate values
  • duplicateClusterLetter - when there are two identical cluster letters
  • invalidClusterLetter - when an option has an invalid cluster letter
  • invalidNumericRange - when a number-valued option has an invalid numeric range
  • invalidParamCount - when a function option has an invalid parameter count
  • invalidInlineConstraint - when a variadic option declares an inline constraint

Errors raised by both the parser and validator

  • enumsConstraintViolation - when a value fails to satisfy either an enumeration constraint or the truth and falsity names
  • regexConstraintViolation - when a value fails to satisfy a string regex constraint
  • rangeConstraintViolation - when a value fails to satisfy a number range constraint
  • limitConstraintViolation - when a value fails to satisfy an array limit constraint

Parsing warnings

  • deprecatedOption - when a deprecated option is specified on the command-line

Validation warnings

  • tooSimilarOptionNames - when an option name is too similar to other names
  • mixedNamingConvention - when a name slot contains names with different naming conventions
  • variadicWithClusterLetter - when a variadic option declares cluster letters

Error phrases

The phrases property specifies the phrases to be used for each kind of error or warning message. It has the following optional properties, whose keys are enumerators from ErrorItem:

  • unknownOption - 'Unknown option (%o|%o1).(| Similar names are: %o2.)'
  • unsatisfiedRequirement - 'Option %o requires %p.'
  • missingRequiredOption - 'Option %o is required.'
  • missingParameter - 'Missing parameter to %o.'
  • missingPackageJson - 'Could not find a "package.json" file.'
  • disallowedInlineParameter - '(Option|Positional marker) %o does not accept inline parameters.'
  • emptyPositionalMarker - 'Option %o has empty positional marker.'
  • unnamedOption - 'Non-positional option %o has no name.'
  • invalidOptionName - 'Option %o has invalid name %s.'
  • invalidVersionDefinition - 'Option %o has empty version.'
  • invalidSelfRequirement - 'Option %o requires itself.'
  • unknownRequiredOption - 'Unknown option %o in requirement.'
  • invalidRequiredOption - 'Invalid option %o in requirement.'
  • invalidRequiredValue- 'Invalid required value for option %o. Option is always required or has a default value.'
  • incompatibleRequiredValue - 'Incompatible required value %v for option %o. Should be of type %s.'
  • emptyEnumsDefinition - 'Option %o has zero-length enumeration.'
  • duplicateOptionName - 'Option %o has duplicate name %s.'
  • duplicatePositionalOption - 'Duplicate positional option %o1: previous was %o2.'
  • duplicateEnumValue - 'Option %o has duplicate enumerator (%s|%n).'
  • enumsConstraintViolation - 'Invalid parameter to %o: (%s1|%n1). Possible values are {(%s2|%n2)}.'
  • regexConstraintViolation - 'Invalid parameter to %o: %s. Value must match the regex %r.'
  • rangeConstraintViolation - 'Invalid parameter to %o: %n1. Value must be in the range [%n2].'
  • limitConstraintViolation - 'Option %o has too many values (%n1). Should have at most %n2.'
  • deprecatedOption - 'Option %o is deprecated and may be removed in future releases.'
  • unsatisfiedCondRequirement - 'Option %o is required if %p.'
  • duplicateClusterLetter - 'Option %o has duplicate cluster letter %s.'
  • invalidClusterOption - 'Option letter %o must be the last in a cluster.'
  • invalidClusterLetter - 'Option %o has invalid cluster letter %s.'
  • tooSimilarOptionNames - '%o: Option name %s1 has too similar names: %s2.'
  • mixedNamingConvention - '%o: Name slot %n has mixed naming conventions: %s.'
  • invalidNumericRange - 'Option %o has invalid numeric range [%n].'
  • invalidParamCount - 'Option %o has invalid parameter count [%n].'
  • variadicWithClusterLetter - 'Variadic option %o may only appear as the last option in a cluster.'
  • missingInlineParameter - 'Option %o requires an inline parameter.'
  • invalidInlineConstraint - 'Inline constraint for option %o has no effect.'
Phrases are formatted according to text formatting rules.

Format specifiers

Error phrases may have format specifiers prefixed with a percent sign %, which get replaced with a value. The following table lists the available specifiers for each kind of error or warning message, along with a description of the corresponding value:

ErrorSpecifiers
unknownOption%o/%o1 = the unknown option name; %o2 = the similar names
unsatisfiedRequirement%o = the specified option name; %p = the option's requirements
missingRequiredOption%o = the option's preferred name
missingParameter%o = the specified option name
disallowedInlineParameter%o = the specified option name or positional marker
emptyPositionalMarker%o = the option's key
unnamedOption%o = the option's key
invalidOptionName%o = the option's key; %s = the invalid name
invalidVersionDefinition%o = the option's key
invalidSelfRequirement%o = the option's key
unknownRequiredOption%o = the required option's key
invalidRequiredOption%o = the required option's key
invalidRequiredValue%o = the required option's key
incompatibleRequiredValue%o = the required option's key; %v = the incompatible value; %s = the expected type
emptyEnumsDefinition%o = the option's key
duplicateOptionName%o = the option's key; %s = the duplicate name
duplicatePositionalOption%o1 = the duplicate option's key; %o2 = the previous option's key
duplicateEnumValue%o = the option's key; %s/%n = the duplicate value
enumsConstraintViolation%o = the option's key or specified name; %s1/%n1 = the specified value; %s2/%n2 = the enum values or the truth and falsity names
regexConstraintViolation%o = the option's key or specified name; %s = the specified value; %r = the regular expression
rangeConstraintViolation%o = the option's key or specified name; %n1 = the specified value; %n2 = the numeric range
limitConstraintViolation%o = the option's key or specified name; %n1 = the element count; %n2 = the count limit
deprecatedOption%o = the specified option name
unsatisfiedCondRequirement%o = the specified option name; %p = the option's requirements
duplicateClusterLetter%o = the option's key; %s = the duplicate letter
invalidClusterOption%o = the specified cluster letter
invalidClusterLetter%o = the option's key; %s = the invalid letter
tooSimilarOptionNames%o = the command prefix1; %s1 = the option name; %s2 = the similar names
mixedNamingConvention%o = the command prefix1; %n = the name slot index; %s = the naming conventions
invalidNumericRange%o = the option's key; %n = the numeric range
invalidParamCount%o = the option's key; %n = the parameter count
variadicWithClusterLetter%o = the option's key
missingInlineParameter%o = the specified option name
invalidInlineConstraint%o = the option's key

Connective words

The connectives property specifies connective words that are used to format some text elements that cannot be customized using phrases, such as option requirements, array element separators and string quoting. This is used in errors, warnings and help messages.

It has the following optional properties, whose keys are enumerators from ConnectiveWord:

  • and - the word used to connect two logical expressions in conjunction (defaults to 'and')
  • or - the word used to connect two logical expressions in disjunction (defaults to 'or')
  • not - the word used to connect a logical expression in negation (defaults to 'not')
  • no - the word used to connect a logical expression in non-existence (defaults to 'no')
  • equals - the word used to connect two expressions in equality comparison (defaults to '==')
  • notEquals - the word used to connect two expressions in non-equality comparison (defaults to '!=')
  • optionAlt - the word used to connect two option names in alternation (defaults to '|')
  • optionSep - the word used to connect two option names in succession (defaults to ',')
  • stringSep - the word used to connect two string values in succession (defaults to ',')
  • numberSep - the word used to connect two number values in succession (defaults to ',')
  • stringQuote - the quote character used to enclose a string value (defaults to "'")

Footnotes

  1. The command prefix is a series of option keys interspersed with periods, denoting the current nested command in a hierarchical option definition. It starts as the empty string and is appended with a nested command's key whenever one is encountered. This prefix also appears in other validation errors, prefixing an option's key in the %o specifier. Here's an example: cmd1.cmd2.flag. 2