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 null
s 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
orundefined
). - 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 tofg.yellow
)string
- the style of string values (defaults tofg.green
)number
- the style of number values (defaults tofg.yellow
)regex
- the style of regular expressions (defaults tofg.red
)option
- the style of option names (defaults tofg.brightMagenta
)value
- the style of unknown values (defaults tofg.brightBlack
)url
- the style of URLs (defaults tofg.brightBlack
)text
- the style of general text (defaults totf.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 suggestionsunsatisfiedRequirement
- when an option requirement is not satisfiedmissingRequiredOption
- when an option that is always required was not specifiedmissingParameter
- when an option parameter is expected but was not specifiedmissingPackageJson
- when it fails to find a "package.json" file when resolving the versiondisallowedInlineParameter
- when either a niladic option or a positional marker is specified with an inline parameterunsatisfiedCondRequirement
- when an option's conditional requirement is not satisfiedinvalidClusterOption
- when either a variadic option or a command option is specified in the middle of a cluster argumentmissingInlineParameter
- when an option is specified without an inline parameter, despite it being required
Validation errors
emptyPositionalMarker
- when a positional option has an empty positional markerunnamedOption
- when a non-positional option has no nameinvalidOptionName
- when an option has an invalid nameinvalidVersionDefinition
- when a version option has an empty version stringinvalidSelfRequirement
- when an option references itself in a requirementunknownRequiredOption
- when an option references an unknown option in a requirementinvalidRequiredOption
- when an option references either a non-valued or an unknown-valued option in a requirementinvalidRequiredValue
- when an option uses a nullish value in a requirement referencing an option that is either always required or has a default valueincompatibleRequiredValue
- when an option is required with a value of incompatible data typeemptyEnumsDefinition
- either an enumeration constraint or the truth and falsity names have zero lengthduplicateOptionName
- when there are two identical option namesduplicatePositionalOption
- when there are two or more positional optionsduplicateEnumValue
- when either an enumeration constraint or the truth and falsity names have duplicate valuesduplicateClusterLetter
- when there are two identical cluster lettersinvalidClusterLetter
- when an option has an invalid cluster letterinvalidNumericRange
- when a number-valued option has an invalid numeric rangeinvalidParamCount
- when a function option has an invalid parameter countinvalidInlineConstraint
- 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 namesregexConstraintViolation
- when a value fails to satisfy a string regex constraintrangeConstraintViolation
- when a value fails to satisfy a number range constraintlimitConstraintViolation
- 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 namesmixedNamingConvention
- when a name slot contains names with different naming conventionsvariadicWithClusterLetter
- 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.'
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:
Error | Specifiers |
---|---|
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
-
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