Skip to content

Commit 961848e

Browse files
committed
feat: add all schema validator in top level compiled schema
1 parent 214bc1e commit 961848e

19 files changed

+498
-332
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 1.5.0
2+
- Added support for all schemas as a high-level entry schema
3+
- Add benchmarks in [`Dartmark`](https://dartmark.dev) website
4+
15
## 1.4.0
26
- Add `RegExp` property in phone validation rule
37

lib/src/contracts/vine.dart

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ abstract interface class ErrorReporter {
55

66
bool hasErrorForField(String fieldName);
77

8-
String format(String rule, FieldContext field, String? message, Map<String, dynamic> options);
8+
String format(String rule, FieldContext field, String? message,
9+
Map<String, dynamic> options);
910

1011
void report(String rule, List<String> keys, String message);
1112

@@ -14,13 +15,12 @@ abstract interface class ErrorReporter {
1415
void clear();
1516
}
1617

17-
abstract interface class ValidatorContract {
18-
}
18+
abstract interface class ValidatorContract {}
1919

2020
abstract interface class VineValidationContext<T extends ErrorReporter> {
2121
T get errorReporter;
2222

23-
Map get data;
23+
dynamic get data;
2424

2525
Map<String, dynamic> getFieldContext(List<String> keys);
2626
}

lib/src/field.dart

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import 'package:vine/src/contracts/vine.dart';
22

3-
final class ValidatorContext<T extends ErrorReporter> implements VineValidationContext<T> {
3+
final class ValidatorContext<T extends ErrorReporter>
4+
implements VineValidationContext<T> {
45
@override
56
final T errorReporter;
67

78
@override
8-
final Map<String, dynamic> data;
9+
final dynamic data;
910

1011
@override
1112
Map<String, dynamic> getFieldContext(List<String> keys) {
@@ -20,7 +21,6 @@ final class ValidatorContext<T extends ErrorReporter> implements VineValidationC
2021
return data;
2122
}
2223

23-
2424
ValidatorContext(this.errorReporter, this.data);
2525
}
2626

lib/src/rule_parser.dart

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import 'dart:collection';
22

3-
import 'package:vine/src/contracts/vine.dart';
4-
import 'package:vine/src/rules/basic_rule.dart';
53
import 'package:vine/vine.dart';
64

75
abstract interface class RuleParserContract {
@@ -37,7 +35,7 @@ class RuleParser implements RuleParserContract {
3735
addRule(VineOptionalRule(), positioned: true);
3836
}
3937

40-
while(rules.isNotEmpty) {
38+
while (rules.isNotEmpty) {
4139
final rule = rules.removeFirst();
4240
rule.handle(ctx, field);
4341

lib/src/rules/basic_rule.dart

+8-4
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ final class VineRequiredIfExistRule implements VineRule {
3535
}
3636

3737
if (!matchs.contains(false) && field.value == null) {
38-
final error = ctx.errorReporter.format('requiredIfExists', field, null, {});
38+
final error =
39+
ctx.errorReporter.format('requiredIfExists', field, null, {});
3940
ctx.errorReporter.report('requiredIfExists', field.customKeys, error);
4041

4142
field.canBeContinue = false;
@@ -61,7 +62,8 @@ final class VineRequiredIfAnyExistRule implements VineRule {
6162
}
6263

6364
if (hasMatch && field.value == null) {
64-
final error = ctx.errorReporter.format('requiredIfExistsAny', field, null, {});
65+
final error =
66+
ctx.errorReporter.format('requiredIfExistsAny', field, null, {});
6567
ctx.errorReporter.report('requiredIfExistsAny', field.customKeys, error);
6668

6769
field.canBeContinue = false;
@@ -84,7 +86,8 @@ final class VineRequiredIfMissingRule implements VineRule {
8486
}
8587

8688
if (!matchs.contains(true) && field.value == null) {
87-
final error = ctx.errorReporter.format('requiredIfMissing', field, null, {});
89+
final error =
90+
ctx.errorReporter.format('requiredIfMissing', field, null, {});
8891
ctx.errorReporter.report('requiredIfMissing', field.customKeys, error);
8992

9093
field.canBeContinue = false;
@@ -110,7 +113,8 @@ final class VineRequiredIfAnyMissingRule implements VineRule {
110113
}
111114

112115
if (!hasMatch && field.value == null) {
113-
final error = ctx.errorReporter.format('requiredIfMissingAny', field, null, {});
116+
final error =
117+
ctx.errorReporter.format('requiredIfMissingAny', field, null, {});
114118
ctx.errorReporter.report('requiredIfMissingAny', field.customKeys, error);
115119

116120
field.canBeContinue = false;

lib/src/rules/enum_rule.dart

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ final class VineEnumRule<T> implements VineRule {
2020
'values': source.map((e) => e.value).toList(),
2121
});
2222

23-
ctx.errorReporter.report('enum', [...field.customKeys, field.name], error);
23+
ctx.errorReporter
24+
.report('enum', [...field.customKeys, field.name], error);
2425
}
2526
}
2627
}

lib/src/rules/object_rule.dart

+5-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ final class VineObjectRule implements VineRule {
1212
@override
1313
void handle(VineValidationContext ctx, FieldContext field) {
1414
final fieldValue = field.value;
15-
if (fieldValue is! Map<String, dynamic>) {
15+
if (fieldValue is! Map) {
1616
final error = ctx.errorReporter.format('object', field, message, {});
1717
ctx.errorReporter.report('object', field.customKeys, error);
1818

@@ -28,16 +28,17 @@ final class VineObjectRule implements VineRule {
2828
final key = entry.key;
2929
final schema = entry.value;
3030

31-
final currentField =
32-
FieldPool.acquire(key, fieldValue.containsKey(key) ? field.value[key] : MissingValue())
31+
final currentField = FieldPool.acquire(
32+
key, fieldValue.containsKey(key) ? field.value[key] : MissingValue())
3333
..customKeys.addAll(List.of(field.customKeys, growable: false));
3434

3535
switch (schema) {
3636
case VineArray():
3737
field.customKeys.add(key);
3838
case VineObject():
3939
if (!fieldValue.containsKey(key)) {
40-
final error = ctx.errorReporter.format('object', field, message, {});
40+
final error =
41+
ctx.errorReporter.format('object', field, message, {});
4142
ctx.errorReporter.report('object', field.customKeys, error);
4243
}
4344
currentField.customKeys.add(key);

lib/src/schema/enum_schema.dart

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
import 'dart:collection';
22

3-
import 'package:vine/src/contracts/schema.dart';
4-
import 'package:vine/src/rule_parser.dart';
5-
import 'package:vine/src/rules/basic_rule.dart';
63
import 'package:vine/vine.dart';
74

8-
final class VineEnumSchema<T extends VineEnumerable> extends RuleParser implements VineEnum {
5+
final class VineEnumSchema<T extends VineEnumerable> extends RuleParser
6+
implements VineEnum {
97
final List<T> _source;
108
VineEnumSchema(super._rules, this._source);
119

lib/src/vine.dart

+7-4
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ import 'package:vine/src/schema/string_schema.dart';
2828
import 'package:vine/src/schema/union_schema.dart';
2929

3030
final class Vine {
31-
ErrorReporter Function(Map<String, String> errors) errorReporter = SimpleErrorReporter.new;
31+
ErrorReporter Function(Map<String, String> errors) errorReporter =
32+
SimpleErrorReporter.new;
3233

3334
VineObject object(Map<String, VineSchema> payload, {String? message}) {
3435
final Queue<VineRule> rules = Queue();
@@ -100,7 +101,8 @@ final class Vine {
100101
return VineDateSchema(rules);
101102
}
102103

103-
Validator compile(VineSchema schema, {Map<String, String> errors = const {}}) {
104+
Validator compile(VineSchema schema,
105+
{Map<String, String> errors = const {}}) {
104106
return Validator(schema.clone(), errors);
105107
}
106108

@@ -128,7 +130,8 @@ final class Validator implements ValidatorContract {
128130

129131
Validator(this._schema, this.errors);
130132

131-
(ValidationException?, Map<String, dynamic>?) tryValidate(Map<String, dynamic> data) {
133+
(ValidationException?, Map<String, dynamic>?) tryValidate(
134+
Map<String, dynamic> data) {
132135
try {
133136
final result = validate(data);
134137
return (null, result);
@@ -137,7 +140,7 @@ final class Validator implements ValidatorContract {
137140
}
138141
}
139142

140-
Map<String, dynamic> validate(Map<String, dynamic> data) {
143+
T validate<T>(dynamic data) {
141144
final validatorContext = ValidatorContext(reporter, data);
142145
final field = Field('', data);
143146
_schema.parse(validatorContext, field);

pubspec.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: vine
22
description: Vine is a robust, typed validation library for Dart/Flutter, designed to simplify and secure data management in applications
3-
version: 1.4.0
3+
version: 1.5.0
44
repository: https://github.com/LeadcodeDev/vine
55

66
platforms:

test/rules/any_test.dart

+8-9
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,25 @@ import 'package:vine/vine.dart';
44

55
void main() {
66
group('VineAny', () {
7+
test('is support any validation on top level', () {
8+
final validator = vine.compile(vine.any());
9+
expect(() => validator.validate('foo'), returnsNormally);
10+
});
11+
712
test('is valid when value is boolean', () {
8-
final validator = vine.compile(vine.object({
9-
'value': vine.boolean()
10-
}));
13+
final validator = vine.compile(vine.object({'value': vine.boolean()}));
1114

1215
expect(() => validator.validate({'value': true}), returnsNormally);
1316
});
1417

1518
test('is valid when value is number', () {
16-
final validator = vine.compile(vine.object({
17-
'value': vine.number()
18-
}));
19+
final validator = vine.compile(vine.object({'value': vine.number()}));
1920

2021
expect(() => validator.validate({'value': 1}), returnsNormally);
2122
});
2223

2324
test('is valid when value is string', () {
24-
final validator = vine.compile(vine.object({
25-
'value': vine.string()
26-
}));
25+
final validator = vine.compile(vine.object({'value': vine.string()}));
2726

2827
expect(() => validator.validate({'value': 'foo'}), returnsNormally);
2928
});

0 commit comments

Comments
 (0)