Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/juancastillo0/valida
Validators for Dart and Flutter. Create field, params and object validators from code annotations.
https://github.com/juancastillo0/valida
dart flutter validation
Last synced: 25 days ago
JSON representation
Validators for Dart and Flutter. Create field, params and object validators from code annotations.
- Host: GitHub
- URL: https://github.com/juancastillo0/valida
- Owner: juancastillo0
- License: mit
- Created: 2021-09-19T14:04:47.000Z (about 3 years ago)
- Default Branch: main
- Last Pushed: 2023-07-09T23:47:43.000Z (over 1 year ago)
- Last Synced: 2024-10-03T08:02:09.793Z (about 1 month ago)
- Topics: dart, flutter, validation
- Language: Dart
- Homepage:
- Size: 266 KB
- Stars: 2
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
[![valida pub package](https://img.shields.io/pub/v/valida.svg)](https://pub.dartlang.org/packages/valida)
[![valida_generator pub package](https://img.shields.io/pub/v/valida_generator.svg)](https://pub.dartlang.org/packages/valida_generator)# valida
Validators for Dart and Flutter. Create field, params and object validators from code annotations.
## Getting Started
Add to pubspec.yaml
```yaml
dependencies:
valida: ^0.0.1
dev_dependencies:
build_runner:
valida_generator: ^0.0.1
```Run `pub get` and create your model class:
```dart
import 'package:valida/valida.dart';part 'model.g.dart';
@Valida(nullableErrorLists: true, customValidate: FormTest._customValidate)
class FormTest {
static List _customValidate(Object? value) {
return [];
}@ValidaString(
minLength: 15,
maxLength: 50,
matches: r'^[a-zA-Z]+$',
customValidate: _customValidateStr,
)
final String longStr;@ValidaString(maxLength: 20, contains: '@')
final String shortStr;@ValidaNum(isInt: true, min: 0, customValidate: _customValidateNum)
final num positiveInt;static List _customValidateNum(num value) {
return [];
}@ValidaFunction()
static List _customValidate2(FormTest value) {
return [
if (value.optionalDecimal == null && value.identifier == null)
ValidaError(
errorCode: 'CustomError.not',
message: 'CustomError message',
property: 'identifier',
value: value,
)
];
}@ValidaFunction()
List _customValidate3() {
return _customValidate2(this);
}@ValidaNum(
min: 0,
max: 1,
comp: ValidaComparison(
less: CompVal(0),
moreEq: CompVal.list([CompVal.ref('positiveInt')]),
),
)
final double? optionalDecimal;@ValidaList(minLength: 1, each: ValidaString(isDate: true, maxLength: 3))
final List nonEmptyList;@ValidaString(isUUID: UUIDVersion.v4)
final String? identifier;final NestedField? nested;
const FormTest({
required this.longStr,
required this.shortStr,
required this.positiveInt,
required this.optionalDecimal,
required this.nonEmptyList,
required this.identifier,
this.nested,
});
}List _customValidateStr(String value) {
// Validate `value` and return a list of errors
return [
if (value == 'WrongValue')
ValidaError(
errorCode: 'CustomError.wrong',
message: 'WrongValue is not allowed',
property: 'longStr',
value: value,
),
];
}@Valida()
class NestedField {
@ValidaString(isTime: true)
final String timeStr;@ValidaDate(min: '2021-01-01')
final DateTime dateWith2021Min;@ValidaDate(max: 'now')
final DateTime? optionalDateWithNowMax;NestedField({
required this.timeStr,
required this.dateWith2021Min,
required this.optionalDateWithNowMax,
});
}```
Execute build_runner to generate the validation code
```
dart pub run build_runner watch --delete-conflicting-outputs
```Use the generated `validateFormTest` with your model
```dart
import 'model.dart'void main() {
const form = FormTest(
longStr: 'long Str',
shortStr: 'shortStr',
positiveInt: 2.4,
optionalDecimal: 3,
nonEmptyList: [],
identifier: 'identifier',
);final FormTestValidation validation = validateFormTest(form);
assert(validation is Validation);
expect(validation.numErrors, validation.allErrors.length);
expect(validation.hasErrors, true);final errorsMap = validation.errorsMap;
expect(errorsMap.isNotEmpty, true);expect(errorsMap[FormTestField.longStr]?.length, 2);
expect(validation.fields.longStr!.length, 2);
expect(errorsMap[FormTestField.shortStr]?.length, 1);
expect(validation.fields.shortStr!.length, 1);
expect(errorsMap[FormTestField.positiveInt]?.length, 1);
expect(validation.fields.positiveInt!.length, 1);
expect(errorsMap[FormTestField.nonEmptyList]?.length, 1);
expect(validation.fields.nonEmptyList!.length, 1);
expect(errorsMap[FormTestField.optionalDecimal]?.length, 2);
expect(validation.fields.optionalDecimal!.length, 2);
}
```The code generator produces the following output
- A function `ModelValidation validateModel(Model)`, that executes the validation
- `ModelValidation` which extends `Validation`, has utility getters for the number of errors, the validated value, whether the validation was successful or not and a `ModelValidationFields` getter
- An enum `ModelField` of the fields for the validated class
- A utility `ModelValidationFields` class which contains named getters for the errors of each field```dart
enum FormTestField {
longStr,
shortStr,
positiveInt,
optionalDecimal,
nonEmptyList,
identifier,
nested,
global,
}class FormTestValidationFields {
const FormTestValidationFields(this.errorsMap);
final Map> errorsMap;NestedFieldValidation? get nested {
final l = errorsMap[FormTestField.nested];
return (l != null && l.isNotEmpty)
? l.first.nestedValidation as NestedFieldValidation?
: null;
}List? get longStr => errorsMap[FormTestField.longStr];
List? get shortStr => errorsMap[FormTestField.shortStr];
List? get positiveInt => errorsMap[FormTestField.positiveInt];
List? get optionalDecimal =>
errorsMap[FormTestField.optionalDecimal];
List? get nonEmptyList => errorsMap[FormTestField.nonEmptyList];
List? get identifier => errorsMap[FormTestField.identifier];
}class FormTestValidation extends Validation {
FormTestValidation(this.errorsMap, this.value, this.fields)
: super(errorsMap);final Map> errorsMap;
final FormTest value;
final FormTestValidationFields fields;
}FormTestValidation validateFormTest(FormTest value) {
final errors = >{};final _nestedValidation = value.nested == null
? null
: validateNestedField(value.nested!).toError(property: 'nested');
errors[FormTestField.nested] = [
if (_nestedValidation != null) _nestedValidation
];errors[FormTestField.global] = [
...FormTest._customValidate2(value),
...value._customValidate3()
];
errors[FormTestField.longStr] = [
..._customValidateStr(value.longStr),
if (value.longStr.length < 15)
ValidaError(
message: r'Should be at a minimum 15 in length',
errorCode: 'ValidaString.minLength',
property: 'longStr',
validationParam: 15,
value: value.longStr,
),
if (value.longStr.length > 50)
ValidaError(
message: r'Should be at a maximum 50 in length',
errorCode: 'ValidaString.maxLength',
property: 'longStr',
validationParam: 50,
value: value.longStr,
),
if (!RegExp(r"^[a-zA-Z]+$").hasMatch(value.longStr))
ValidaError(
message: r'Should match ^[a-zA-Z]+$',
errorCode: 'ValidaString.matches',
property: 'longStr',
validationParam: RegExp(r"^[a-zA-Z]+$"),
value: value.longStr,
)
];
// ...
// More validations
// ...
errors[FormTestField.nonEmptyList] = [
if (value.nonEmptyList.length < 1)
ValidaError(
message: r'Should be at a minimum 1 in length',
errorCode: 'ValidaList.minLength',
property: 'nonEmptyList',
validationParam: 1,
value: value.nonEmptyList,
)
];
errors.removeWhere((k, v) => v.isEmpty);return FormTestValidation(
errors,
value,
FormTestValidationFields(errors),
);
}enum NestedFieldField {
timeStr,
dateWith2021Min,
optionalDateWithNowMax,
}class NestedFieldValidationFields {
const NestedFieldValidationFields(this.errorsMap);
final Map> errorsMap;List get timeStr => errorsMap[NestedFieldField.timeStr]!;
List get dateWith2021Min =>
errorsMap[NestedFieldField.dateWith2021Min]!;
List get optionalDateWithNowMax =>
errorsMap[NestedFieldField.optionalDateWithNowMax]!;
}class NestedFieldValidation extends Validation {
NestedFieldValidation(this.errorsMap, this.value, this.fields)
: super(errorsMap);final Map> errorsMap;
final NestedField value;
final NestedFieldValidationFields fields;
}NestedFieldValidation validateNestedField(NestedField value) {
final errors = >{};errors[NestedFieldField.dateWith2021Min] = [
if (DateTime.fromMillisecondsSinceEpoch(1609459200000)
.isAfter(value.dateWith2021Min))
ValidaError(
message: r'Should be at a minimum 2021-01-01',
errorCode: 'ValidaDate.min',
property: 'dateWith2021Min',
validationParam: "2021-01-01",
value: value.dateWith2021Min,
)
];
if (value.optionalDateWithNowMax == null)
errors[NestedFieldField.optionalDateWithNowMax] = [];
else
errors[NestedFieldField.optionalDateWithNowMax] = [
if (DateTime.now().isAfter(value.optionalDateWithNowMax!))
ValidaError(
message: r'Should be at a maximum now',
errorCode: 'ValidaDate.max',
property: 'optionalDateWithNowMax',
validationParam: "now",
value: value.optionalDateWithNowMax!,
)
];return NestedFieldValidation(
errors,
value,
NestedFieldValidationFields(errors),
);
}```