Ask Validators

Overview

DCli ships with a number built in validators for use with the ask function.

When a validator is applied to the ask method, the ask method will not return until the user enters a value that satisfies the validator.

If you pass required: false toask, then the validator won't be called if the user input is empty!

In addition to the built-in validators, you can also create your own custom validators and combine multiple validators.

Combining Validators

The DCli Ask command allows you to combine multiple validators with the Ask.any and Ask.all validators.

Ask.all

The Ask.all validator takes an array of validators.

All validators must succeed for the input to be considered valid. The validators are processed in the order they are passed (left to right). The error from the first validator that fails is displayed.

The Ask.all validator is the equivalent of a boolean AND operator.

It should be noted that the user input is passed to each validator in turn and each validator has the opportunity to modify the input. As a result, each validator will be operating on a version of the input that has been processed by all validators that appear earlier in the list.

 var password = ask( 'Password?', hidden: true
      , validator: Ask.all([Ask.alphaNumeric, AskLength(10,16)]));

The password must be composed of alphanumeric characters and be between 10 and 16 characters long.

Ask.any

The Ask.any validator takes an array of validators.

Only one of the validators must succeed for the input to be considered valid. The validators are processed in the order they are passed (left to right). If no validators pass, then the error from the first validator is displayed.

The Ask.any validator is the equivalent of a boolean OR operator.

It should be noted that the user input is passed to each validator in turn and each validator has the opportunity to modify the input. As a result, each validator will be operating on a version of the input that has been processed by all validators that appear earlier in the list.

If none of the validators pass then the error from the first validator that failed is displayed. The implication is that the user will only ever see the error from the first validator.

 var password = ask( 'Password?', hidden: true
      , validator: Ask.all([Ask.alphaNumeric, AskValidatorLength(10,16)]));

Standard Ask Validators

The set of standard Ask Validators allows you to validate common input requirements. You can combine them with the Ask.all and Ask.any methods to allow for more complicated validation.

All of the standard Ask Validators allow the user to enter a blank value

If you only want the validator applied if a user enters a value, then pass 'required: false' to the ask function.

Ask.ipAddress

Validates that the entered value is an IP address. By default, both IPv4 and IPv6 addresses are permitted.

To restrict the IP address to a specific version, pass in the expected version.

var ipAddress = ask( 'Server IP?',  validator: Ask.ipAddress());
var ipV4Address = ask( 'Merchant IP?'
    , validator: Ask.ipAddress(AskValidatorIPAddress.ipv4));

Ask.lengthMax

Validates that the input is no longer than the provided maximum.

var username = ask( 'username?', validator: Ask.lengthMax(32));

Ask.lengthMin

Validates that the input is no shorter than the provided minimum.

var username = ask( 'username?', validator: Ask.lengthMin(26));

Ask.lengthRange

Validates that the input is no shorter than the provided minimum and no longer than the provided max.

var username = ask( 'username?', validator: Ask.lengthRange(26, 32));

Ask.inList

Validates that the input is contained in the provided list.

You are often better off using a menu.

Set the caseSensitive to true to do a case-sensitive comparison against the list. Defaults to false.

The list may contain strings or any Dart Object.

The toString method is called on each object passed to the list to obtain the comparison string.

var sex = ask( 'sex?', validator: Ask.inList(['male', 'female']));

Ask.email

Validates that the user input is a valid email address.

var email = ask( 'Email Address?', validator: Ask.email));

Ask.fqdn

Validates that the user input is a valid Fully Qualified Domain Name (www.onepub.dev) address.

var email = ask( 'FQDN?', validator: Ask.fqdn));

Ask.integer

Validates that the user input is a valid integer.

The integer is returned as a string.

var ageAsString = ask( 'Age?', validator: Ask.integer));
var age = int.parse(ageAsString);

Ask.valueRange

Validates that an entered number is within the provided range (inclusive). Can be used with both integer and decimal no.s

The value is returned as a string.

var age = ask('Age?', 
    validator: Ask.all([Ask.integer, Ask.valueRange(18, 25)]));

Ask.decimal

Validates that the user input is a valid decimal number.

The decimal is returned as a string.

var age = ask( 'Age?', validator: Ask.decimal));

Ask.alpha

Validates that the user input is an alpha string with every character in the range [a-zA-Z].

var name = ask( 'name?', validator: Ask.alpha));

Ask.alphaNumeric

Validates that the user input is a alphaNumeric string with every character in the range [a-zA-Z0-9].

var name = ask( 'name?', validator: Ask.alpha));

Custom Validators

You can also write your own validators.

All validators must inherit from the AskValidator class and implement the validate method.

The validator method must return the passed line but may alter the line before returning it. The altered results are what will be returned from the ask function.

a validator MUST not include the value of the 'line' in an error message as you risk exposing a password that the user is entering.

If the ask function uses one of the combination validators (Ask.all, Ask.any) then the line input by the user will be passed to each validator in turn. Each validator may change the line and that altered value will be passed to the next validator. In this way, the entered value may go through multiple transformations before being returned to the caller.

class AskGoodOrBad extends AskValidator {
  const AskGoodOrBad();
  @override
  String validate(String line) {
    line = line.trim();

    if (line != 'good' && line != 'bad') {
      throw AskValidatorException(red('The response must be good | bad'));
    }
    return line;
  }
}

To use your your new validator:

var getsPresent = ask('Have you been good or bad'
    , validator:  AskGoodOrBad());

Async Validators

An Ask validator must return a synchronous type. If you need to make an async call from within validator then you need to use the waitForEx function to strip the async nature of the call.

class AskAsync extends AskValidator {
  const AskAsync ();
  @override
  String validate(String line) {
    line = line.trim();
    
    if (checkInput(line) == false)
    {
      throw AskValidatorException(red("The entered line wasn't valid"));
    }
    return line;
  }
  
  Future<bool> checkInput(String line) async {
    // make some async call to check [line]
  }
}

Last updated