简化验证

一个受 FP 启发的验证 DSL。适用于 Dart 和 Flutter 项目。

特点

  • 完全可扩展(创建您自己的组合器、验证器原语等)
  • Flexible Verify 是一个基于扩展的 API(没有创建单个类,全是纯函数)
  • 可定制(如果需要,定义您自己的错误类型)以任何您想要的方式组织验证器
  • Bloc 友好(请参阅 示例 以获得具体的实现)
  • Null 安全(预览版)

用法

创建验证器

验证器只是一个简单的函数别名

// One of 2 variats depending on wether the validated subject will be transformed into another type or not
typedef ValidatorT<S, T> = Either<List<dynamic>, T> Function(S subject);
typedef Validator<S> = Either<List<dynamic>, S> Function(S subject);

因此,您可以通过仅指定一个函数来创建自己的验证器,例如

final Validator<String> emailValidator = (String email) {
  return email.contains('@') ? Right(email) : Left('Bad email format')
};

从谓词创建简单的验证器

更简单的方法是使用一些内置的辅助函数。

final contains@ = Verify.that(
  (String email) => email.contains('@'),
    error: 'Bad email format'
    );

使用自定义错误并通过类型进行过滤

重用验证器

使用组合来构建更复杂的验证器。

final Validator<String> emailValidator = Verify.all([ contains@, notEmpty ])

验证和转换

验证器也能够转换它们的输入,所以例如我们可以这样做
一次性完成解析和验证。

final Validator<String, int> intParsingValidator = (String str) => Right(int.parse(str));

final validator = intParsingValidator.onException((_) => Error('not an integer'));

字段验证

给定一个模型,例如一个用户

class User extends Equatable {
  final String? phone;
  final String? mail;
  final int? age;

  const User(this.phone, this.mail, this.age);

  @override
  List<Object> get props => [phone ?? '', mail ?? '', age ?? ''];
}

可以通过链接一系列 check
checkField 方法对对象及其字段执行额外的检查。

final userValidator = Verify.empty<User>()
    .check((user) => !user.phone!.isEmpty, error: Error('phone empty'))
    .checkField((user) => user.mail!, emailValidator);

final someUser = User('','', 25);
final Either<List<Error>, User> validationResult = userValidator.verify(someUser);

注意:check 和 checkField 的区别在于后者会在值为空时忽略验证,
这在支持 Null 安全的下一版本中可能会改变。

运行验证器

运行验证器就像传递一个参数一样简单,因为它只是一个函数。
为了更清晰地说明,提供了一个 verify 方法,这个方法很特别,因为它除了
将参数转发给调用验证器之外,还可以用于过滤错误列表并
将其转换为特定错误类型。只需提供一个特定的类型参数。

final signUpValidation = Verify.subject<SignUpState>();
final errors = signUpValidation
    .verify<SignUpError>(newState); // Either<List<SignUpError>, SignUpState>

内置验证器

Verify 没有自带很多内置验证器,因为它们非常容易创建。

它确实带有一些正则表达式的简写。

final validator = Verify.fromRegex(RegExp(r"(^\d+$)", error: Error('not just digits')) // Validator<String, int>

表单验证

通常您会为您的错误类型建模类似于

enum FormField {
  email,
  password,
  passwordConfirmation,
}

class SignUpError extends ValidationError {
  final String message;
  final FormField field;

  SignUpError(this.message, {required this.field});

  @override
  String get errorDescription => message;
}

在这些情况下,能够按字段对错误进行分组会很方便。

Verify 为此提供的解决方案是

final validator = Verify.inOrder<SignUpFormState>([
  validateMail,
  validatePassword,
  validateConfirmation,
]);

final Map<FormField, SignUpError> errorMap = validator
    .verify<SignUpError>(someState)
    .groupedErrorsBy((error) => error.field);

顺序执行

可以使用一个略有不同的 API 来实现与 inOrder 组合函数相同的结果。

final numberValidator = Verify.subject<int>()
  .then(Verify.that(
    (subject) => subject % 2 == 0,
    error: Error('not even'),
  ))
  .then(Verify.that(
    (subject) => subject >= 10,
    error: Error('single digit'),
  ));

final errors2 = numberValidator.errors(3); // yields 1 error
final errors = numberValidator.errors(4); // yields 1 error

这样您就可以快速访问按字段分段的错误。

GitHub

https://github.com/DanielCardonaRojas/verify