validart 1.0.0
validart: ^1.0.0 copied to clipboard
A type-safe validation library for Dart, inspired by Zod. Supports parse/safeParse, transforms, coercion, schema composition, and structured errors.
example/example.dart
import 'package:validart/validart.dart';
void main() {
// String validation
final nameSchema = V.string()
..min(3)
..max(50);
print(nameSchema.validate('Alice')); // true
print(nameSchema.validate('Al')); // false
// Email validation
final emailSchema = V.string()..email();
print(emailSchema.validate('alice@example.com')); // true
print(emailSchema.validate('invalid')); // false
// Integer validation
final ageSchema = V.int()
..min(0)
..max(150);
print(ageSchema.validate(25)); // true
print(ageSchema.validate(-1)); // false
// Map validation (structured data)
final userSchema = V.map({
'name': V.string()..min(1),
'email': V.string()..email(),
'age': V.int()
..min(0)
..nullable(),
});
print(
userSchema.validate({'name': 'Alice', 'email': 'alice@ex.com'})); // true
print(userSchema.errors({'name': '', 'email': 'bad'})); // list of VError
// Object validation (entities/classes)
final folderSchema = V.object<Folder>(
configure: (o) => o
.field('id', (f) => f.id, V.string()..uuid())
.field('name', (f) => f.name, V.string()..min(1)),
);
final folder =
Folder(id: '550e8400-e29b-41d4-a716-446655440000', name: 'Docs');
print(folderSchema.validate(folder)); // true
// Array validation with indexed errors
final emailsSchema = V.string().email().array()
..min(1)
..unique();
print(emailsSchema.validate(['a@b.com', 'c@d.com'])); // true
final result = emailsSchema.safeParse(['a@b.com', 'bad', 'a@b.com']);
if (result case VFailure(:final errors)) {
for (final error in errors) {
print('${error.pathString}: ${error.message}');
}
}
// Coercion
final coercedInt = V.coerce.int();
print(coercedInt.parse('42')); // 42
// Enum validation
final statusSchema = V.enm(Status.values);
print(statusSchema.validate(Status.active)); // true
// Literal validation
final adminSchema = V.literal('admin');
print(adminSchema.validate('admin')); // true
print(adminSchema.validate('user')); // false
// Union validation
final idSchema = V.union([V.string()..uuid(), V.int()..min(1)]);
print(idSchema.validate('550e8400-e29b-41d4-a716-446655440000')); // true
print(idSchema.validate(42)); // true
// Custom locale (i18n)
V.setLocale(const VLocale({
'invalid_email': 'Email inválido',
'positive': 'Deve ser positivo',
'required': 'Campo obrigatório',
}));
final ptSchema = V.string()..email();
print(ptSchema.errors('bad')?.first.message); // 'Email inválido'
// Reset to default
V.setLocale(const VLocale());
// Schema composition
final baseSchema = V.map({
'name': V.string()..min(1),
'email': V.string()..email(),
});
final createSchema = baseSchema.extend({
'password': V.string()..min(8),
});
print(createSchema.validate({
'name': 'Alice',
'email': 'a@b.com',
'password': '12345678',
})); // true
// Parse with transforms
final trimmedEmail = V.string()
..trim()
..toLowerCase()
..email();
print(trimmedEmail.parse(' ALICE@EXAMPLE.COM ')); // 'alice@example.com'
// Not empty
final notEmptySchema = V.string()..notEmpty();
print(notEmptySchema.validate('')); // false
print(notEmptySchema.validate(' ')); // true (whitespace is not empty)
// Password confirmation with equalFields
final registerSchema = V.map({
'password': V.string()..min(8),
'confirm': V.string(),
})
..equalFields('confirm', 'password');
print(registerSchema.validate({
'password': '12345678',
'confirm': '12345678',
})); // true
// Conditional validation with when
final formSchema = V.map({
'type': V.string(),
'cnpj': V.string()..nullable(),
'cpf': V.string()..nullable(),
})
..when('type', equals: 'company', then: {
'cnpj': V.string()..min(14),
})
..when('type', equals: 'person', then: {
'cpf': V.string()..min(11),
});
print(formSchema
.validate({'type': 'company', 'cnpj': '12345678901234'})); // true
print(formSchema.validate({'type': 'person', 'cpf': '12345678901'})); // true
// Transform — change output type
final lengthSchema = V.string().transform<int>((s) => s.length);
print(lengthSchema.parse('hello')); // 5
// Preprocess — transform before type check
final preprocessSchema = V.string()
..preprocess((v) => v?.toString().trim() ?? '');
print(preprocessSchema.parse(42)); // '42'
// Form errors as Map
final formResult = V.map({
'email': V.string()..email(),
'name': V.string()..min(3),
}).safeParse({'email': 'bad', 'name': 'Al'});
if (formResult case VFailure()) {
print(formResult.toMap());
// {email: Invalid email address, name: Must be at least 3 characters}
}
}
class Folder {
final String id;
final String name;
Folder({required this.id, required this.name});
}
enum Status { active, inactive }