formix_validators

Built-in validation rules for the Formix ecosystem. Includes validators for strings, numbers, dates, collections, phone numbers, and files.

Installation

dependencies:
  formix_validators: ^0.1.0
  formix_core: ^0.1.0

Available Validators

  • StringRules - String validation (required, email, length, patterns, etc.)
  • NumberRules - Numeric validation (range, positive, precision, etc.)
  • DateRules - Date/time validation (past, future, age, weekday, etc.)
  • CollectionRules - Collection validation (length, unique, contains, etc.)
  • PhoneRules - Phone number validation
  • FileRules - File validation (size, extension, etc.)

StringRules

import 'package:formix_validators/formix_validators.dart';

// Required (non-empty)
StringRules.required(error: 'Field is required')

// Trimmed not empty (ignores whitespace)
StringRules.trimmedNotEmpty(error: 'Cannot be blank')

// Length constraints
StringRules.minLength(8, error: 'Must be at least 8 characters')
StringRules.maxLength(100, error: 'Must be at most 100 characters')
StringRules.lengthRange(3, 20, error: 'Must be 3-20 characters')

// Email validation
StringRules.email(error: 'Invalid email format')

// Pattern matching
StringRules.matches(RegExp(r'^[a-zA-Z0-9_]+$'), error: 'Invalid characters')

// String content
StringRules.startsWith('+', error: 'Must start with +')
StringRules.endsWith('.com', error: 'Must end with .com')
StringRules.contains('@', error: 'Must contain @')
StringRules.equals(otherValue, error: 'Values must match')
StringRules.equalsIgnoreCase('yes', error: 'Must be yes')

// Character requirements
StringRules.hasUppercase(error: 'Must contain uppercase letter')
StringRules.hasLowercase(error: 'Must contain lowercase letter')
StringRules.hasDigit(error: 'Must contain a number')
StringRules.hasSpecialChar(error: 'Must contain special character')

// Format validators
StringRules.digitsOnly(error: 'Only digits allowed')
StringRules.alphaOnly(error: 'Only letters allowed')
StringRules.alphanumeric(error: 'Only letters and numbers allowed')
StringRules.url(error: 'Invalid URL')
StringRules.uuid(error: 'Invalid UUID')
StringRules.creditCard(error: 'Invalid credit card number')

Complete Email Validator Example

final emailValidator = Validate.all<String, String>([
  StringRules.required(error: 'Email is required'),
  StringRules.email(error: 'Invalid email format'),
  StringRules.maxLength(255, error: 'Email too long'),
]);

Password Validator Example

final passwordValidator = Validate.all<String, String>([
  StringRules.required(error: 'Password is required'),
  StringRules.minLength(8, error: 'Must be at least 8 characters'),
  StringRules.hasUppercase(error: 'Must contain uppercase letter'),
  StringRules.hasLowercase(error: 'Must contain lowercase letter'),
  StringRules.hasDigit(error: 'Must contain a number'),
  StringRules.hasSpecialChar(error: 'Must contain special character'),
]);

NumberRules

import 'package:formix_validators/formix_validators.dart';

// Basic constraints
NumberRules.min(0, error: 'Must be non-negative')
NumberRules.max(100, error: 'Must be at most 100')
NumberRules.range(1, 100, error: 'Must be 1-100')

// Comparison
NumberRules.greaterThan(0, error: 'Must be positive')
NumberRules.lessThan(100, error: 'Must be less than 100')

// Sign validation
NumberRules.positive(error: 'Must be positive')
NumberRules.nonNegative(error: 'Cannot be negative')
NumberRules.negative(error: 'Must be negative')
NumberRules.nonPositive(error: 'Must be non-positive')

// Special values
NumberRules.notZero(error: 'Cannot be zero')
NumberRules.finite(error: 'Must be a finite number')

// Integer constraints
NumberRules.integer(error: 'Must be a whole number')
NumberRules.even(error: 'Must be even')
NumberRules.odd(error: 'Must be odd')
NumberRules.multipleOf(5, error: 'Must be multiple of 5')

// Decimal precision
NumberRules.maxDecimalPlaces(2, error: 'Max 2 decimal places')

Age Validator Example

final ageValidator = Validate.all<int, String>([
  NumberRules.range(0, 150, error: 'Invalid age'),
]);

// With string input transformation
final ageFromString = Validate.transform<String, int, String>(
  transform: (value) => int.tryParse(value),
  onNull: 'Must be a number',
  then: ageValidator,
);

Price Validator Example

final priceValidator = Validate.all<double, String>([
  NumberRules.nonNegative(error: 'Price cannot be negative'),
  NumberRules.maxDecimalPlaces(2, error: 'Max 2 decimal places'),
  NumberRules.max(1000000, error: 'Price too high'),
]);

DateRules

import 'package:formix_validators/formix_validators.dart';

// Relative to now
DateRules.past(error: 'Must be in the past')
DateRules.future(error: 'Must be in the future')

// Relative to another date
DateRules.before(deadline, error: 'Must be before deadline')
DateRules.after(startDate, error: 'Must be after start date')
DateRules.range(startDate, endDate, error: 'Must be within range')

// Weekday validation
DateRules.weekday([1, 2, 3, 4, 5], error: 'Must be a weekday')
DateRules.businessDay(error: 'Must be a business day (Mon-Fri)')

// Age validation
DateRules.age(18, 120, error: 'Must be 18-120 years old')
DateRules.minAge(18, error: 'Must be at least 18 years old')
DateRules.maxAge(65, error: 'Must be under 65 years old')

Birth Date Validator Example

final birthDateValidator = Validate.all<DateTime, String>([
  DateRules.past(error: 'Birth date must be in the past'),
  DateRules.age(0, 150, error: 'Invalid birth date'),
]);

Appointment Date Validator Example

final appointmentValidator = Validate.all<DateTime, String>([
  DateRules.future(error: 'Appointment must be in the future'),
  DateRules.businessDay(error: 'Must be a business day'),
  DateRules.range(
    DateTime.now(),
    DateTime.now().add(Duration(days: 90)),
    error: 'Must be within 90 days',
  ),
]);

CollectionRules

import 'package:formix_validators/formix_validators.dart';

// Length constraints
CollectionRules.notEmpty(error: 'Cannot be empty')
CollectionRules.minLength(1, error: 'At least one item required')
CollectionRules.maxLength(10, error: 'Maximum 10 items')
CollectionRules.lengthRange(1, 5, error: 'Must have 1-5 items')

// Uniqueness
CollectionRules.unique(error: 'No duplicates allowed')
CollectionRules.uniqueBy((item) => item.id, error: 'Duplicate IDs')

// Content checks
CollectionRules.contains(item, error: 'Must include item')
CollectionRules.containsAll([item1, item2], error: 'Missing required items')
CollectionRules.containsAny([item1, item2], error: 'Must include at least one')
CollectionRules.doesNotContain(item, error: 'Must not include item')

// Element validation
CollectionRules.every(predicate, error: 'All items must match')
CollectionRules.any(predicate, error: 'At least one must match')
CollectionRules.none(predicate, error: 'None should match')

Tags Validator Example

final tagsValidator = Validate.all<List<String>, String>([
  CollectionRules.minLength(1, error: 'At least one tag required'),
  CollectionRules.maxLength(5, error: 'Maximum 5 tags'),
  CollectionRules.unique(error: 'Duplicate tags not allowed'),
  CollectionRules.every(
    (tag) => tag.length <= 20,
    error: 'Tags must be 20 characters or less',
  ),
]);

Using with Custom Error Types

All validators support custom error types via generics:

// With enum errors
enum EmailError { required, invalidFormat, tooLong }

final validator = Validate.all<String, EmailError>([
  StringRules.required(error: EmailError.required),
  StringRules.email(error: EmailError.invalidFormat),
  StringRules.maxLength(255, error: EmailError.tooLong),
]);

// With sealed class errors (recommended for i18n)
sealed class PasswordError {}
class PasswordRequired extends PasswordError {}
class PasswordTooShort extends PasswordError {
  final int minLength;
  PasswordTooShort(this.minLength);
}

final validator = Validate.all<String, PasswordError>([
  StringRules.required(error: PasswordRequired()),
  StringRules.minLength(8, error: PasswordTooShort(8)),
]);

Combining Validators

// Complete user registration validator
final usernameValidator = Validate.all<String, String>([
  StringRules.required(error: 'Username is required'),
  StringRules.minLength(3, error: 'Too short'),
  StringRules.maxLength(20, error: 'Too long'),
  StringRules.alphanumeric(error: 'Only letters and numbers'),
]);

final emailValidator = Validate.all<String, String>([
  StringRules.required(error: 'Email is required'),
  StringRules.email(error: 'Invalid email'),
]);

final passwordValidator = Validate.allCollect<String, String>([
  StringRules.required(error: 'Password is required'),
  StringRules.minLength(8, error: 'At least 8 characters'),
  StringRules.hasUppercase(error: 'Need uppercase'),
  StringRules.hasDigit(error: 'Need number'),
]);

License

MIT License - see LICENSE file for details.

Libraries

collections
Collection validation rules for the Formix ecosystem.
date
DateTime validation rules for the Formix ecosystem.
file
File validation rules for the Formix ecosystem.
formix_validators
Consolidated validation rules for the Formix ecosystem.
number
Number validation rules for the Formix ecosystem.
phone
Phone number validation rules for the Formix ecosystem.
string
String validation rules for the Formix ecosystem.