validate static method

Future<ValidationResult> validate(
  1. Map<String, dynamic> data,
  2. Map<String, String> rules, [
  3. Map<String, String>? customMessages
])

Validates the data against the provided rules.

Implementation

static Future<ValidationResult> validate(
  Map<String, dynamic> data,
  Map<String, String> rules, [
  Map<String, String>? customMessages,
]) async {
  final errors = <String, List<String>>{};
  final validatedData = <String, dynamic>{};

  // 1. Expand wildcards (e.g. items.*.name)
  final expandedRules = <String, String>{};
  for (final entry in rules.entries) {
    if (entry.key.contains('*')) {
      final matches = _expandWildcardPath(data, entry.key);
      for (final match in matches) {
        expandedRules[match] = entry.value;
      }
    } else {
      expandedRules[entry.key] = entry.value;
    }
  }

  // 2. Process all rules (including expanded ones)
  for (final entry in expandedRules.entries) {
    final field = entry.key;
    final ruleString = entry.value;
    final fieldRules = ruleString.split('|');
    final value = _getNestedValue(data, field);

    var fieldFailed = false;
    final shouldBail = fieldRules.contains('bail');

    for (final rule in fieldRules) {
      if (rule == 'bail') continue;

      var ruleName = rule;
      String? arg;
      if (rule.contains(':')) {
        final parts = rule.split(':');
        ruleName = parts[0];
        arg = parts[1];
      }

      final handler = ruleHandlers[ruleName];
      if (handler != null) {
        final passed = await handler(value, arg, data);
        if (!passed) {
          final message = _getMessage(field, ruleName, arg, customMessages);
          errors[field] ??= [];
          errors[field]!.add(message);
          fieldFailed = true;

          // Short-circuit on first failure if bail is set or if required fails
          if (shouldBail || ruleName == 'required') break;
        }
      }
    }

    if (!fieldFailed) {
      _setNestedValue(validatedData, field, _coerceValue(value, fieldRules));
    }
  }

  return ValidationResult(errors, validatedData);
}