From a87276275a02aae65dd95e0770d0ada9251e05ec Mon Sep 17 00:00:00 2001 From: Baptiste Parmantier Date: Fri, 5 Sep 2025 21:46:05 +0200 Subject: [PATCH 1/2] wip --- lib/src/error_reporter.dart | 6 +++++- lib/src/rule_parser.dart | 1 + lib/src/rules/object_rule.dart | 1 + lib/src/schema/object/object_schema.dart | 8 +++++++- lib/src/vine.dart | 19 ++++++++++++++++++- test/rules/number_test.dart | 16 ++++++++++++++++ 6 files changed, 48 insertions(+), 3 deletions(-) diff --git a/lib/src/error_reporter.dart b/lib/src/error_reporter.dart index 9a7f6d6..0d90b8a 100755 --- a/lib/src/error_reporter.dart +++ b/lib/src/error_reporter.dart @@ -36,7 +36,11 @@ class SimpleErrorReporter implements VineErrorReporter { @override void report(String rule, List keys, String message) { hasError = true; - errors.add({'message': message, 'rule': rule, 'field': keys.join('.')}); + errors.add({ + 'message': message, + 'rule': rule, + if (keys.isNotEmpty) 'field': keys.join('.') + }); } @override diff --git a/lib/src/rule_parser.dart b/lib/src/rule_parser.dart index 010f32f..0b2aec5 100755 --- a/lib/src/rule_parser.dart +++ b/lib/src/rule_parser.dart @@ -37,6 +37,7 @@ class RuleParser implements RuleParserContract { while (rules.isNotEmpty) { final rule = rules.removeFirst(); + rule.handle(ctx, field); if (!field.canBeContinue) break; diff --git a/lib/src/rules/object_rule.dart b/lib/src/rules/object_rule.dart index 9d924f6..5c19942 100755 --- a/lib/src/rules/object_rule.dart +++ b/lib/src/rules/object_rule.dart @@ -2,6 +2,7 @@ import 'package:vine/src/contracts/rule.dart'; import 'package:vine/src/contracts/schema.dart'; import 'package:vine/src/contracts/vine.dart'; import 'package:vine/src/field_pool.dart'; +import 'package:vine/vine.dart'; final class VineObjectRule implements VineRule { final Map payload; diff --git a/lib/src/schema/object/object_schema.dart b/lib/src/schema/object/object_schema.dart index eeadda5..cb02e9d 100755 --- a/lib/src/schema/object/object_schema.dart +++ b/lib/src/schema/object/object_schema.dart @@ -4,6 +4,7 @@ import 'package:vine/src/contracts/schema.dart'; import 'package:vine/src/contracts/vine.dart'; import 'package:vine/src/rule_parser.dart'; import 'package:vine/src/rules/basic_rule.dart'; +import 'package:vine/vine.dart'; final class VineObjectSchema extends RuleParser implements VineObject { final Map _properties; @@ -63,7 +64,12 @@ final class VineObjectSchema extends RuleParser implements VineObject { @override VineObject clone() { - return VineObjectSchema({..._properties}, Queue.of(rules)); + final Map props = {}; + for (final entry in _properties.entries) { + props[entry.key] = entry.value.clone(); + } + + return VineObjectSchema(props, Queue.of(rules)); } @override diff --git a/lib/src/vine.dart b/lib/src/vine.dart index 28d5f17..673c17c 100644 --- a/lib/src/vine.dart +++ b/lib/src/vine.dart @@ -144,7 +144,24 @@ final class Validator implements VineValidatorContract { T validate(dynamic data) { final validatorContext = VineValidatorContext(reporter, data); final field = VineField('', data); - _schema.parse(validatorContext, field); + + // if (_schema case VineObjectSchema object) { + // for (final property in object.properties.entries) { + // if (property.value case VineNumberSchema number) { + // print(['initial', property.key, number.rules]); + // } + // } + // } + + // if (schema case VineObjectSchema object) { + // for (final property in object.properties.entries) { + // if (property.value case VineNumberSchema number) { + // print(['derived', property.key, number.rules]); + // } + // } + // } + + schema.parse(validatorContext, field); if (reporter.hasError) { throw reporter.createError({'errors': reporter.errors}); diff --git a/test/rules/number_test.dart b/test/rules/number_test.dart index fe1d4fe..0e1ab78 100755 --- a/test/rules/number_test.dart +++ b/test/rules/number_test.dart @@ -301,5 +301,21 @@ void main() { expect(() => validator.validate({'age': 'not a number'}), throwsA(isA())); }); + + test('indepedant test', () { + final validator = vine.compile(vine.object({ + 'toto': vine.number().min(18).optional(), + })); + + final payload = {'toto': 25}; + + expect(() => validator.validate(payload), returnsNormally); + expect(() { + return validator.validate({ + ...payload, + 'toto': 17, + }); + }, throwsA(isA())); + }, tags: ['test']); }); } From e727ca867aa204542bcf3880b187d48f148b31d2 Mon Sep 17 00:00:00 2001 From: Baptiste Parmantier Date: Sat, 6 Sep 2025 00:44:17 +0200 Subject: [PATCH 2/2] feat: improve performance and validation architecture The changes show a significant refactoring of the validation architecture with the following key updates: - Convert rule storage from Queue to List for better performance - Remove field pooling optimization in favor of simpler code - Simplify rule parsing by removing positioned rules - Move nullable/optional rules to beginning of rules list - Streamline object/array schema validation flow - Update performance benchmark results in README - Fix various smaller validation issues This refactoring prioritizes code clarity and maintainability while retaining solid validation capabilities. --- README.md | 10 ++-- benchmark/array_object.dart | 17 +++--- benchmark/flat_object.dart | 3 +- lib/src/field.dart | 2 +- lib/src/field_pool.dart | 23 --------- lib/src/rule_parser.dart | 30 ++--------- lib/src/rules/array_rule.dart | 21 ++------ lib/src/rules/object_rule.dart | 7 +-- lib/src/rules/union_rule.dart | 5 +- lib/src/schema/any_schema.dart | 18 +++---- lib/src/schema/array_schema.dart | 24 ++++----- lib/src/schema/boolean_schema.dart | 22 ++++---- lib/src/schema/date_schema.dart | 30 +++++------ lib/src/schema/enum_schema.dart | 28 +++++----- lib/src/schema/number_schema.dart | 30 +++++------ lib/src/schema/object/group_schema.dart | 8 ++- lib/src/schema/object/object_schema.dart | 12 ++--- lib/src/schema/string_schema.dart | 66 ++++++++++++------------ lib/src/schema/union_schema.dart | 18 +++---- lib/src/vine.dart | 40 ++++---------- test/rules/number_test.dart | 4 +- test/test.test.dart | 14 ----- 22 files changed, 159 insertions(+), 273 deletions(-) delete mode 100644 lib/src/field_pool.dart delete mode 100644 test/test.test.dart diff --git a/README.md b/README.md index bae4f74..3c5b495 100755 --- a/README.md +++ b/README.md @@ -14,13 +14,13 @@ ensuring that data complies with an expected format before it is used, which red ## 🛠 Key features | Feature | Description | -|---------------------------|--------------------------------------------------------------| -| ✅ Type-Safe Validation | Define schemas with a fluent API and ensure data integrity | +| ------------------------- | ------------------------------------------------------------ | +| ✅ Type-Safe Validation | Define schemas with a fluent API and ensure data integrity | | 🧱 Rich Set of Validators | Strings, numbers, booleans, arrays, enums, objects, and more | | 🔄 Data Transformation | Trim, normalize, and transform values during validation | | 🚧 Null Safety | Full support for nullable and optional fields | | ⚙️ Composable | Compiled and reusable schemas | -| ⚡ Fast Performance | ~ 29 000 000 ops/s | +| ⚡ Fast Performance | ~ 3 000 000 ops/s | | 📦 Extremely small size | Package size `< 21kb` | | 🚀 OpenApi reporter | Export your schemas as OpenApi spec | @@ -86,7 +86,7 @@ void main() { ### OpenAPI reporter -Vine can generate an OpenAPI schema from your validation schemas. +Vine can generate an OpenAPI schema from your validation schemas. This feature is useful when you want to document your API ```dart @@ -111,4 +111,4 @@ print(reporter); I would like to thank [Harminder Virk](https://github.com/thetutlage) for all his open-source work on Adonis.js and for his permission to -reuse the name `Vine` for this package. +reuse the name `Vine` for this package. diff --git a/benchmark/array_object.dart b/benchmark/array_object.dart index 7e3b1fa..87e8dc3 100644 --- a/benchmark/array_object.dart +++ b/benchmark/array_object.dart @@ -1,19 +1,16 @@ import 'package:vine/src/vine.dart'; void main() { - final validator = vine.compile(vine.object({ - 'contacts': vine.array(vine.object({ + final validator = vine.compile(vine.array( + vine.object({ 'type': vine.string(), 'value': vine.string().optional(), - })), - })); + }), + )); - final payload = { - 'contacts': [ - {'type': 'email', 'value': 'foo@bar.com'}, - {'type': 'phone', 'value': '12345678'}, - ], - }; + final payload = [ + {'type': 'email', 'value': 'foo@bar.com'}, + ]; final duration = Duration(seconds: 1); int iterationCount = 0; diff --git a/benchmark/flat_object.dart b/benchmark/flat_object.dart index d35dbd9..baaa857 100644 --- a/benchmark/flat_object.dart +++ b/benchmark/flat_object.dart @@ -20,5 +20,6 @@ void main() { iterationCount++; } - print('Flat Object : Processed $iterationCount iterations in ${duration.inSeconds} seconds'); + print( + 'Flat Object : Processed $iterationCount iterations in ${duration.inSeconds} seconds'); } diff --git a/lib/src/field.dart b/lib/src/field.dart index 980b4b9..80bb169 100755 --- a/lib/src/field.dart +++ b/lib/src/field.dart @@ -26,7 +26,7 @@ final class VineValidatorContext final class VineField implements VineFieldContext { @override - final List customKeys = []; + List customKeys = []; @override String name; diff --git a/lib/src/field_pool.dart b/lib/src/field_pool.dart deleted file mode 100644 index e78e666..0000000 --- a/lib/src/field_pool.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'dart:collection'; - -import 'package:vine/vine.dart'; - -class VineFieldPool { - static final _pool = Queue(); - static final int _maxSize = 1000; - - static VineField acquire(String name, dynamic value) { - if (_pool.isEmpty) return VineField(name, value); - return _pool.removeFirst() - ..name = name - ..value = value - ..canBeContinue = true - ..customKeys.clear(); - } - - static void release(VineField field) { - if (_pool.length < _maxSize) { - _pool.add(field); - } - } -} diff --git a/lib/src/rule_parser.dart b/lib/src/rule_parser.dart index 0b2aec5..b22367e 100755 --- a/lib/src/rule_parser.dart +++ b/lib/src/rule_parser.dart @@ -1,43 +1,21 @@ -import 'dart:collection'; - import 'package:vine/vine.dart'; abstract interface class RuleParserContract { - Queue get rules; - void addRule(VineRule rule, {bool positioned = false}); + List get rules; } class RuleParser implements RuleParserContract { @override - Queue rules; + List rules; bool isNullable = false; bool isOptional = false; RuleParser(this.rules); - @override - void addRule(VineRule rule, {bool positioned = false}) { - if (positioned) { - rules.addFirst(rule); - return; - } - - rules.add(rule); - } - VineFieldContext parse(VineValidationContext ctx, VineFieldContext field) { - if (isNullable) { - addRule(VineNullableRule(), positioned: true); - } - - if (isOptional) { - addRule(VineOptionalRule(), positioned: true); - } - - while (rules.isNotEmpty) { - final rule = rules.removeFirst(); - + for (int i = 0; i < rules.length; i++) { + final rule = rules[i]; rule.handle(ctx, field); if (!field.canBeContinue) break; diff --git a/lib/src/rules/array_rule.dart b/lib/src/rules/array_rule.dart index f4d35aa..ed67525 100755 --- a/lib/src/rules/array_rule.dart +++ b/lib/src/rules/array_rule.dart @@ -1,8 +1,7 @@ import 'package:vine/src/contracts/rule.dart'; import 'package:vine/src/contracts/schema.dart'; import 'package:vine/src/contracts/vine.dart'; -import 'package:vine/src/field_pool.dart'; -import 'package:vine/src/rule_parser.dart'; +import 'package:vine/src/field.dart'; final class VineArrayRule implements VineRule { final VineSchema schema; @@ -11,27 +10,13 @@ final class VineArrayRule implements VineRule { @override void handle(VineValidationContext ctx, VineFieldContext field) { - final copy = field.customKeys; - if (field.value case List values) { - final currentSchema = schema as RuleParser; - final copyRules = currentSchema.rules.toList(); - for (int i = 0; i < values.length; i++) { - final currentField = VineFieldPool.acquire(field.name, values[i]); - - currentSchema.rules.clear(); - currentSchema.rules.addAll(copyRules); + final currentField = VineField(field.name, values[i]) + ..customKeys = [...field.customKeys, i.toString()]; - currentField.customKeys.add(i.toString()); schema.parse(ctx, currentField); - - currentField.customKeys - ..clear() - ..addAll(copy); - currentField.mutate([...field.value, currentField.value]); - VineFieldPool.release(currentField); } return; diff --git a/lib/src/rules/object_rule.dart b/lib/src/rules/object_rule.dart index 5c19942..86d4b83 100755 --- a/lib/src/rules/object_rule.dart +++ b/lib/src/rules/object_rule.dart @@ -1,7 +1,3 @@ -import 'package:vine/src/contracts/rule.dart'; -import 'package:vine/src/contracts/schema.dart'; -import 'package:vine/src/contracts/vine.dart'; -import 'package:vine/src/field_pool.dart'; import 'package:vine/vine.dart'; final class VineObjectRule implements VineRule { @@ -29,7 +25,7 @@ final class VineObjectRule implements VineRule { final key = entry.key; final schema = entry.value; - final currentField = VineFieldPool.acquire( + final currentField = VineField( key, fieldValue.containsKey(key) ? field.value[key] : MissingValue()) ..customKeys.addAll(List.of(field.customKeys, growable: false)); @@ -50,7 +46,6 @@ final class VineObjectRule implements VineRule { resultMap[key] = currentField.value; shouldBreak = !currentField.canBeContinue || ctx.errorReporter.hasError; - VineFieldPool.release(currentField); } final cleanedMap = { diff --git a/lib/src/rules/union_rule.dart b/lib/src/rules/union_rule.dart index 2889192..b6def40 100755 --- a/lib/src/rules/union_rule.dart +++ b/lib/src/rules/union_rule.dart @@ -1,7 +1,7 @@ import 'package:vine/src/contracts/rule.dart'; import 'package:vine/src/contracts/schema.dart'; import 'package:vine/src/contracts/vine.dart'; -import 'package:vine/src/field_pool.dart'; +import 'package:vine/vine.dart'; final class VineUnionRule implements VineRule { final List schemas; @@ -12,7 +12,7 @@ final class VineUnionRule implements VineRule { void handle(VineValidationContext ctx, VineFieldContext field) { final List errors = []; field.customKeys.add(field.name); - final currentField = VineFieldPool.acquire(field.name, field.value); + final currentField = VineField(field.name, field.value); currentField.isUnion = true; for (final schema in schemas) { @@ -23,7 +23,6 @@ final class VineUnionRule implements VineRule { } } currentField.isUnion = false; - VineFieldPool.release(currentField); if (errors.length == schemas.length) { final error = ctx.errorReporter.format('union', field, null, { diff --git a/lib/src/schema/any_schema.dart b/lib/src/schema/any_schema.dart index ae5499d..c0b0455 100755 --- a/lib/src/schema/any_schema.dart +++ b/lib/src/schema/any_schema.dart @@ -1,5 +1,3 @@ -import 'dart:collection'; - import 'package:vine/src/contracts/schema.dart'; import 'package:vine/src/contracts/vine.dart'; import 'package:vine/src/rule_parser.dart'; @@ -12,43 +10,43 @@ final class VineAnySchema extends RuleParser implements VineAny { @override VineAny transform(Function(VineValidationContext, VineFieldContext) fn) { - super.addRule(VineTransformRule(fn)); + super.rules.add(VineTransformRule(fn)); return this; } @override VineAny requiredIfExist(List values) { - super.addRule(VineRequiredIfExistRule(values), positioned: true); + super.rules = [VineRequiredIfExistRule(values), ...super.rules]; return this; } @override VineAny requiredIfAnyExist(List values) { - super.addRule(VineRequiredIfAnyExistRule(values), positioned: true); + super.rules = [VineRequiredIfAnyExistRule(values), ...rules]; return this; } @override VineAny requiredIfMissing(List values) { - super.addRule(VineRequiredIfMissingRule(values), positioned: true); + super.rules = [VineRequiredIfMissingRule(values), ...rules]; return this; } @override VineAny requiredIfAnyMissing(List values) { - super.addRule(VineRequiredIfAnyMissingRule(values), positioned: true); + super.rules = [VineRequiredIfAnyMissingRule(values), ...rules]; return this; } @override VineAny nullable() { - super.isNullable = true; + super.rules = [VineNullableRule(), ...rules]; return this; } @override VineAny optional() { - super.isOptional = true; + super.rules = [VineOptionalRule(), ...rules]; return this; } @@ -60,7 +58,7 @@ final class VineAnySchema extends RuleParser implements VineAny { @override VineAny clone() { - return VineAnySchema(Queue.of(rules)); + return VineAnySchema([...rules]); } @override diff --git a/lib/src/schema/array_schema.dart b/lib/src/schema/array_schema.dart index 0ef127d..2e0cc32 100755 --- a/lib/src/schema/array_schema.dart +++ b/lib/src/schema/array_schema.dart @@ -12,73 +12,73 @@ final class VineArraySchema extends RuleParser implements VineArray { @override VineArray minLength(int value, {String? message}) { - super.addRule(VineArrayMinLengthRule(value, message)); + super.rules.add(VineArrayMinLengthRule(value, message)); return this; } @override VineArray maxLength(int value, {String? message}) { - super.addRule(VineArrayMaxLengthRule(value, message)); + super.rules.add(VineArrayMaxLengthRule(value, message)); return this; } @override VineArray fixedLength(int value, {String? message}) { - super.addRule(VineArrayFixedLengthRule(value, message)); + super.rules.add(VineArrayFixedLengthRule(value, message)); return this; } @override VineArray unique({String? message}) { - super.addRule(VineArrayUniqueRule(message)); + super.rules.add(VineArrayUniqueRule(message)); return this; } @override VineArray transform(Function(VineValidationContext, VineFieldContext) fn) { - super.addRule(VineTransformRule(fn)); + super.rules.add(VineTransformRule(fn)); return this; } @override VineArray requiredIfExist(List values) { - super.addRule(VineRequiredIfExistRule(values), positioned: true); + super.rules = [VineRequiredIfExistRule(values), ...super.rules]; return this; } @override VineArray requiredIfAnyExist(List values) { - super.addRule(VineRequiredIfAnyExistRule(values), positioned: true); + super.rules = [VineRequiredIfAnyExistRule(values), ...rules]; return this; } @override VineArray requiredIfMissing(List values) { - super.addRule(VineRequiredIfMissingRule(values), positioned: true); + super.rules = [VineRequiredIfMissingRule(values), ...rules]; return this; } @override VineArray requiredIfAnyMissing(List values) { - super.addRule(VineRequiredIfAnyMissingRule(values), positioned: true); + super.rules = [VineRequiredIfAnyMissingRule(values), ...rules]; return this; } @override VineArray nullable() { - super.isNullable = true; + super.rules = [VineNullableRule(), ...rules]; return this; } @override VineArray optional() { - super.isOptional = true; + super.rules = [VineOptionalRule(), ...rules]; return this; } @override VineArray clone() { - return VineArraySchema(Queue.of(rules)); + return VineArraySchema([...rules]); } int? _getRuleValue() { diff --git a/lib/src/schema/boolean_schema.dart b/lib/src/schema/boolean_schema.dart index 634deaa..f92e35f 100755 --- a/lib/src/schema/boolean_schema.dart +++ b/lib/src/schema/boolean_schema.dart @@ -1,5 +1,3 @@ -import 'dart:collection'; - import 'package:vine/src/contracts/schema.dart'; import 'package:vine/src/contracts/vine.dart'; import 'package:vine/src/rule_parser.dart'; @@ -12,43 +10,43 @@ final class VineBooleanSchema extends RuleParser implements VineBoolean { @override VineBoolean transform(Function(VineValidationContext, VineFieldContext) fn) { - super.addRule(VineTransformRule(fn)); + super.rules.add(VineTransformRule(fn)); return this; } @override VineBoolean requiredIfExist(List values) { - super.addRule(VineRequiredIfExistRule(values), positioned: true); + super.rules = [VineRequiredIfExistRule(values), ...super.rules]; return this; } @override VineBoolean requiredIfAnyExist(List values) { - super.addRule(VineRequiredIfAnyExistRule(values), positioned: true); + super.rules = [VineRequiredIfAnyExistRule(values), ...rules]; return this; } @override VineBoolean requiredIfMissing(List values) { - super.addRule(VineRequiredIfMissingRule(values), positioned: true); + super.rules = [VineRequiredIfMissingRule(values), ...rules]; return this; } @override VineBoolean requiredIfAnyMissing(List values) { - super.addRule(VineRequiredIfAnyMissingRule(values), positioned: true); + super.rules = [VineRequiredIfAnyMissingRule(values), ...rules]; return this; } @override - VineBoolean nullable() { - super.isNullable = true; + VineBoolean optional() { + super.rules = [VineOptionalRule(), ...rules]; return this; } @override - VineBoolean optional() { - super.isOptional = true; + VineBoolean nullable() { + super.rules = [VineNullableRule(), ...rules]; return this; } @@ -60,7 +58,7 @@ final class VineBooleanSchema extends RuleParser implements VineBoolean { @override VineBoolean clone() { - return VineBooleanSchema(Queue.of(rules)); + return VineBooleanSchema([...rules]); } @override diff --git a/lib/src/schema/date_schema.dart b/lib/src/schema/date_schema.dart index 6d63e52..72fb1f5 100755 --- a/lib/src/schema/date_schema.dart +++ b/lib/src/schema/date_schema.dart @@ -1,5 +1,3 @@ -import 'dart:collection'; - import 'package:vine/src/contracts/schema.dart'; import 'package:vine/src/contracts/vine.dart'; import 'package:vine/src/rule_parser.dart'; @@ -13,79 +11,79 @@ final class VineDateSchema extends RuleParser implements VineDate { @override VineDate before(DateTime value, {String? message}) { - super.addRule(VineDateBeforeRule(value, message)); + super.rules.add(VineDateBeforeRule(value, message)); return this; } @override VineDate after(DateTime value, {String? message}) { - super.addRule(VineDateAfterRule(value, message)); + super.rules.add(VineDateAfterRule(value, message)); return this; } @override VineDate between(DateTime min, DateTime max, {String? message}) { - super.addRule(VineDateBetweenRule(min, max, message)); + super.rules.add(VineDateBetweenRule(min, max, message)); return this; } @override VineDate beforeField(String target, {String? message}) { - super.addRule(VineDateBeforeFieldRule(target, message)); + super.rules.add(VineDateBeforeFieldRule(target, message)); return this; } @override VineDate afterField(String target, {String? message}) { - super.addRule(VineDateAfterFieldRule(target, message)); + super.rules.add(VineDateAfterFieldRule(target, message)); return this; } @override VineDate betweenFields(String start, String end, {String? message}) { - super.addRule(VineDateBetweenFieldRule(start, end, message)); + super.rules.add(VineDateBetweenFieldRule(start, end, message)); return this; } @override VineDate transform(Function(VineValidationContext, VineFieldContext) fn) { - super.addRule(VineTransformRule(fn)); + super.rules.add(VineTransformRule(fn)); return this; } @override VineDate requiredIfExist(List values) { - super.addRule(VineRequiredIfExistRule(values), positioned: true); + super.rules = [VineRequiredIfExistRule(values), ...super.rules]; return this; } @override VineDate requiredIfAnyExist(List values) { - super.addRule(VineRequiredIfAnyExistRule(values), positioned: true); + super.rules = [VineRequiredIfAnyExistRule(values), ...rules]; return this; } @override VineDate requiredIfMissing(List values) { - super.addRule(VineRequiredIfMissingRule(values), positioned: true); + super.rules = [VineRequiredIfMissingRule(values), ...rules]; return this; } @override VineDate requiredIfAnyMissing(List values) { - super.addRule(VineRequiredIfAnyMissingRule(values), positioned: true); + super.rules = [VineRequiredIfAnyMissingRule(values), ...rules]; return this; } @override VineDate nullable() { - super.isNullable = true; + super.rules = [VineNullableRule(), ...rules]; return this; } @override VineDate optional() { - super.isOptional = true; + super.rules = [VineOptionalRule(), ...rules]; return this; } @@ -97,7 +95,7 @@ final class VineDateSchema extends RuleParser implements VineDate { @override VineDate clone() { - return VineDateSchema(Queue.of(rules)); + return VineDateSchema([...rules]); } @override diff --git a/lib/src/schema/enum_schema.dart b/lib/src/schema/enum_schema.dart index f7f5d6c..b1bd3e2 100755 --- a/lib/src/schema/enum_schema.dart +++ b/lib/src/schema/enum_schema.dart @@ -1,5 +1,3 @@ -import 'dart:collection'; - import 'package:vine/vine.dart'; final class VineEnumSchema extends RuleParser @@ -10,44 +8,44 @@ final class VineEnumSchema extends RuleParser VineEnumSchema(super._rules, this._source); @override - VineEnum requiredIfExist(List values) { - super.addRule(VineRequiredIfExistRule(values), positioned: true); + VineEnum transform(Function(VineValidationContext, VineFieldContext) fn) { + super.rules.add(VineTransformRule(fn)); return this; } @override - VineEnum requiredIfAnyExist(List values) { - super.addRule(VineRequiredIfAnyExistRule(values), positioned: true); + VineEnum requiredIfExist(List values) { + super.rules = [VineRequiredIfExistRule(values), ...super.rules]; return this; } @override - VineEnum requiredIfMissing(List values) { - super.addRule(VineRequiredIfMissingRule(values), positioned: true); + VineEnum requiredIfAnyExist(List values) { + super.rules = [VineRequiredIfAnyExistRule(values), ...rules]; return this; } @override - VineEnum requiredIfAnyMissing(List values) { - super.addRule(VineRequiredIfAnyMissingRule(values), positioned: true); + VineEnum requiredIfMissing(List values) { + super.rules = [VineRequiredIfMissingRule(values), ...rules]; return this; } @override - VineEnum transform(Function(VineValidationContext, VineFieldContext) fn) { - super.addRule(VineTransformRule(fn)); + VineEnum requiredIfAnyMissing(List values) { + super.rules = [VineRequiredIfAnyMissingRule(values), ...rules]; return this; } @override VineEnum nullable() { - super.isNullable = true; + super.rules = [VineNullableRule(), ...rules]; return this; } @override VineEnum optional() { - super.isOptional = true; + super.rules = [VineOptionalRule(), ...rules]; return this; } @@ -59,7 +57,7 @@ final class VineEnumSchema extends RuleParser @override VineEnum clone() { - return VineEnumSchema(Queue.of(rules), _source.toList()); + return VineEnumSchema([...rules], _source.toList()); } @override diff --git a/lib/src/schema/number_schema.dart b/lib/src/schema/number_schema.dart index 23131a0..288a2a5 100755 --- a/lib/src/schema/number_schema.dart +++ b/lib/src/schema/number_schema.dart @@ -13,85 +13,85 @@ final class VineNumberSchema extends RuleParser implements VineNumber { @override VineNumber range(List values, {String? message}) { - super.addRule(VineRangeRule(values, message)); + super.rules.add(VineRangeRule(values, message)); return this; } @override VineNumber min(num value, {String? message}) { - super.addRule(VineMinRule(value, message)); + super.rules.add(VineMinRule(value, message)); return this; } @override VineNumber max(num value, {String? message}) { - super.addRule(VineMaxRule(value, message)); + super.rules.add(VineMaxRule(value, message)); return this; } @override VineNumber negative({String? message}) { - super.addRule(VineNegativeRule(message)); + super.rules.add(VineNegativeRule(message)); return this; } @override VineNumber positive({String? message}) { - super.addRule(VinePositiveRule(message)); + super.rules.add(VinePositiveRule(message)); return this; } @override VineNumber double({String? message}) { - super.addRule(VineDoubleRule(message)); + super.rules.add(VineDoubleRule(message)); return this; } @override VineNumber integer({String? message}) { - super.addRule(VineIntegerRule(message)); + super.rules.add(VineIntegerRule(message)); return this; } @override VineNumber requiredIfExist(List values) { - super.addRule(VineRequiredIfExistRule(values), positioned: true); + super.rules = [VineRequiredIfExistRule(values), ...super.rules]; return this; } @override VineNumber requiredIfAnyExist(List values) { - super.addRule(VineRequiredIfAnyExistRule(values), positioned: true); + super.rules = [VineRequiredIfAnyExistRule(values), ...rules]; return this; } @override VineNumber requiredIfMissing(List values) { - super.addRule(VineRequiredIfMissingRule(values), positioned: true); + super.rules = [VineRequiredIfMissingRule(values), ...rules]; return this; } @override VineNumber requiredIfAnyMissing(List values) { - super.addRule(VineRequiredIfAnyMissingRule(values), positioned: true); + super.rules = [VineRequiredIfAnyMissingRule(values), ...rules]; return this; } @override VineNumber transform(Function(VineValidationContext, VineFieldContext) fn) { - super.addRule(VineTransformRule(fn)); + super.rules.add(VineTransformRule(fn)); return this; } @override VineNumber nullable() { - super.isNullable = true; + super.rules = [VineNullableRule(), ...rules]; return this; } @override VineNumber optional() { - super.isOptional = true; + super.rules = [VineOptionalRule(), ...rules]; return this; } @@ -103,7 +103,7 @@ final class VineNumberSchema extends RuleParser implements VineNumber { @override VineNumber clone() { - return VineNumberSchema(Queue.of(rules)); + return VineNumberSchema([...rules]); } @override diff --git a/lib/src/schema/object/group_schema.dart b/lib/src/schema/object/group_schema.dart index 6bfac83..06f4e42 100644 --- a/lib/src/schema/object/group_schema.dart +++ b/lib/src/schema/object/group_schema.dart @@ -1,5 +1,3 @@ -import 'dart:collection'; - import 'package:vine/src/rules/group_object_rule.dart'; import 'package:vine/vine.dart'; @@ -9,19 +7,19 @@ final class VineGroupSchema extends RuleParser implements VineGroup { @override VineGroup when(bool Function(Map data) fn, Map object) { - super.addRule(VineObjectGroupRule(fn, object)); + super.rules.add(VineObjectGroupRule(fn, object)); return this; } @override VineGroup otherwise(Function(VineValidationContext, VineFieldContext) fn) { - super.addRule(VineObjectOtherwiseRule(fn)); + super.rules.add(VineObjectOtherwiseRule(fn)); return this; } @override VineGroup clone() { - return VineGroupSchema(Queue.of(rules)); + return VineGroupSchema([...rules]); } @override diff --git a/lib/src/schema/object/object_schema.dart b/lib/src/schema/object/object_schema.dart index cb02e9d..cc556f8 100755 --- a/lib/src/schema/object/object_schema.dart +++ b/lib/src/schema/object/object_schema.dart @@ -22,31 +22,31 @@ final class VineObjectSchema extends RuleParser implements VineObject { @override VineObject transform(Function(VineValidationContext, VineFieldContext) fn) { - super.addRule(VineTransformRule(fn)); + super.rules.add(VineTransformRule(fn)); return this; } @override VineObject requiredIfExist(List values) { - super.addRule(VineRequiredIfExistRule(values), positioned: true); + super.rules = [VineRequiredIfExistRule(values), ...super.rules]; return this; } @override VineObject requiredIfAnyExist(List values) { - super.addRule(VineRequiredIfAnyExistRule(values), positioned: true); + super.rules = [VineRequiredIfAnyExistRule(values), ...rules]; return this; } @override VineObject requiredIfMissing(List values) { - super.addRule(VineRequiredIfMissingRule(values), positioned: true); + super.rules = [VineRequiredIfMissingRule(values), ...rules]; return this; } @override VineObject requiredIfAnyMissing(List values) { - super.addRule(VineRequiredIfAnyMissingRule(values), positioned: true); + super.rules = [VineRequiredIfAnyMissingRule(values), ...rules]; return this; } @@ -69,7 +69,7 @@ final class VineObjectSchema extends RuleParser implements VineObject { props[entry.key] = entry.value.clone(); } - return VineObjectSchema(props, Queue.of(rules)); + return VineObjectSchema(props, [...rules]); } @override diff --git a/lib/src/schema/string_schema.dart b/lib/src/schema/string_schema.dart index 235a19c..e21e085 100755 --- a/lib/src/schema/string_schema.dart +++ b/lib/src/schema/string_schema.dart @@ -1,5 +1,3 @@ -import 'dart:collection'; - import 'package:vine/vine.dart'; final class VineStringSchema extends RuleParser implements VineString { @@ -9,37 +7,37 @@ final class VineStringSchema extends RuleParser implements VineString { @override VineString minLength(int value, {String? message}) { - super.addRule(VineMinLengthRule(value, message)); + super.rules.add(VineMinLengthRule(value, message)); return this; } @override VineString maxLength(int value, {String? message}) { - super.addRule(VineMaxLengthRule(value, message)); + super.rules.add(VineMaxLengthRule(value, message)); return this; } @override VineString fixedLength(int value, {String? message}) { - super.addRule(VineFixedLengthRule(value, message)); + super.rules.add(VineFixedLengthRule(value, message)); return this; } @override VineString email({String? message}) { - super.addRule(VineEmailRule(message)); + super.rules.add(VineEmailRule(message)); return this; } @override VineString phone({RegExp? match, String? message}) { - super.addRule(VinePhoneRule(match, message)); + super.rules.add(VinePhoneRule(match, message)); return this; } @override VineString ipAddress({IpAddressVersion? version, String? message}) { - super.addRule(VineIpAddressRule(version, message)); + super.rules.add(VineIpAddressRule(version, message)); return this; } @@ -50,153 +48,153 @@ final class VineStringSchema extends RuleParser implements VineString { bool requireProtocol = false, bool allowUnderscores = false, String? message}) { - super.addRule(VineUrlRule( + super.rules.add(VineUrlRule( protocols, requireTld, requireProtocol, allowUnderscores, message)); return this; } @override VineString alpha({String? message}) { - super.addRule(VineAlphaRule(message)); + super.rules.add(VineAlphaRule(message)); return this; } @override VineString alphaNumeric({String? message}) { - super.addRule(VineAlphaNumericRule(message)); + super.rules.add(VineAlphaNumericRule(message)); return this; } @override VineString startsWith(String value, {String? message}) { - super.addRule(VineStartWithRule(value, message)); + super.rules.add(VineStartWithRule(value, message)); return this; } @override VineString endsWith(String value, {String? message}) { - super.addRule(VineEndWithRule(value, message)); + super.rules.add(VineEndWithRule(value, message)); return this; } @override VineString confirmed( {String? property, bool include = false, String? message}) { - super.addRule(VineConfirmedRule(property, include, message)); + super.rules.add(VineConfirmedRule(property, include, message)); return this; } @override VineString regex(RegExp expression, {String? message}) { - super.addRule(VineRegexRule(expression, message)); + super.rules.add(VineRegexRule(expression, message)); return this; } @override VineString trim() { - super.addRule(VineTrimRule()); + super.rules.add(VineTrimRule()); return this; } @override VineString normalizeEmail({bool lowercase = true}) { - super.addRule(VineNormalizeEmailRule(lowercase)); + super.rules.add(VineNormalizeEmailRule(lowercase)); return this; } @override VineString toUpperCase() { - super.addRule(VineUpperCaseRule()); + super.rules.add(VineUpperCaseRule()); return this; } @override VineString toLowerCase() { - super.addRule(VineLowerCaseRule()); + super.rules.add(VineLowerCaseRule()); return this; } @override VineString toCamelCase() { - super.addRule(VineToCamelCaseRule()); + super.rules.add(VineToCamelCaseRule()); return this; } @override VineString uuid({UuidVersion? version, String? message}) { - super.addRule(VineUuidRule(version, message)); + super.rules.add(VineUuidRule(version, message)); return this; } @override VineString isCreditCard({String? message}) { - super.addRule(VineCreditCardRule(message)); + super.rules.add(VineCreditCardRule(message)); return this; } @override VineString sameAs(String value, {String? message}) { - super.addRule(VineSameAsRule(value, message)); + super.rules.add(VineSameAsRule(value, message)); return this; } @override VineString notSameAs(String value, {String? message}) { - super.addRule(VineNotSameAsRule(value, message)); + super.rules.add(VineNotSameAsRule(value, message)); return this; } @override VineString inList(List values, {String? message}) { - super.addRule(VineInListRule(values, message)); + super.rules.add(VineInListRule(values, message)); return this; } @override VineString notInList(List values, {String? message}) { - super.addRule(VineNotInListRule(values, message)); + super.rules.add(VineNotInListRule(values, message)); return this; } @override VineString requiredIfExist(List values) { - super.addRule(VineRequiredIfExistRule(values), positioned: true); + super.rules = [VineRequiredIfExistRule(values), ...super.rules]; return this; } @override VineString requiredIfAnyExist(List values) { - super.addRule(VineRequiredIfAnyExistRule(values), positioned: true); + super.rules = [VineRequiredIfAnyExistRule(values), ...rules]; return this; } @override VineString requiredIfMissing(List values) { - super.addRule(VineRequiredIfMissingRule(values), positioned: true); + super.rules = [VineRequiredIfMissingRule(values), ...rules]; return this; } @override VineString requiredIfAnyMissing(List values) { - super.addRule(VineRequiredIfAnyMissingRule(values), positioned: true); + super.rules = [VineRequiredIfAnyMissingRule(values), ...rules]; return this; } @override VineString transform(Function(VineValidationContext, VineFieldContext) fn) { - super.addRule(VineTransformRule(fn)); + super.rules.add(VineTransformRule(fn)); return this; } @override VineString nullable() { - super.isNullable = true; + super.rules = [VineNullableRule(), ...rules]; return this; } @override VineString optional() { - super.isOptional = true; + super.rules = [VineOptionalRule(), ...rules]; return this; } @@ -208,7 +206,7 @@ final class VineStringSchema extends RuleParser implements VineString { @override VineString clone() { - return VineStringSchema(Queue.of(rules)); + return VineStringSchema([...rules]); } @override diff --git a/lib/src/schema/union_schema.dart b/lib/src/schema/union_schema.dart index 8799a6c..cfe912a 100644 --- a/lib/src/schema/union_schema.dart +++ b/lib/src/schema/union_schema.dart @@ -1,5 +1,3 @@ -import 'dart:collection'; - import 'package:vine/vine.dart'; final class VineUnionSchema extends RuleParser implements VineUnion { @@ -10,43 +8,43 @@ final class VineUnionSchema extends RuleParser implements VineUnion { @override VineUnion requiredIfExist(List values) { - super.addRule(VineRequiredIfExistRule(values), positioned: true); + super.rules = [VineRequiredIfExistRule(values), ...super.rules]; return this; } @override VineUnion requiredIfAnyExist(List values) { - super.addRule(VineRequiredIfAnyExistRule(values), positioned: true); + super.rules = [VineRequiredIfAnyExistRule(values), ...rules]; return this; } @override VineUnion requiredIfMissing(List values) { - super.addRule(VineRequiredIfMissingRule(values), positioned: true); + super.rules = [VineRequiredIfMissingRule(values), ...rules]; return this; } @override VineUnion requiredIfAnyMissing(List values) { - super.addRule(VineRequiredIfAnyMissingRule(values), positioned: true); + super.rules = [VineRequiredIfAnyMissingRule(values), ...rules]; return this; } @override VineUnion transform(Function(VineValidationContext, VineFieldContext) fn) { - super.addRule(VineTransformRule(fn)); + super.rules.add(VineTransformRule(fn)); return this; } @override VineUnion nullable() { - super.isNullable = true; + super.rules = [VineNullableRule(), ...rules]; return this; } @override VineUnion optional() { - super.isOptional = true; + super.rules = [VineOptionalRule(), ...rules]; return this; } @@ -58,7 +56,7 @@ final class VineUnionSchema extends RuleParser implements VineUnion { @override VineUnion clone() { - return VineUnionSchema(Queue.of(rules), _schemas.toList()); + return VineUnionSchema([...rules], _schemas.toList()); } @override diff --git a/lib/src/vine.dart b/lib/src/vine.dart index 673c17c..e4db8cd 100644 --- a/lib/src/vine.dart +++ b/lib/src/vine.dart @@ -1,5 +1,3 @@ -import 'dart:collection'; - import 'package:vine/src/contracts/rule.dart'; import 'package:vine/src/contracts/schema.dart'; import 'package:vine/src/contracts/vine.dart'; @@ -32,13 +30,13 @@ final class Vine { SimpleErrorReporter.new; VineObject object(Map payload, {String? message}) { - final Queue rules = Queue(); + final List rules = []; rules.add(VineObjectRule(payload, message)); return VineObjectSchema(payload, rules); } VineGroup group(Function(VineGroupSchema) builder) { - final Queue rules = Queue(); + final List rules = []; final group = VineGroupSchema(rules); builder(group); @@ -46,56 +44,56 @@ final class Vine { } VineString string({String? message}) { - final Queue rules = Queue(); + final List rules = []; rules.add(VineStringRule(message)); return VineStringSchema(rules); } VineNumber number({String? message}) { - final Queue rules = Queue(); + final List rules = []; rules.add(VineNumberRule(message)); return VineNumberSchema(rules); } VineBoolean boolean({bool includeLiteral = false, String? message}) { - final Queue rules = Queue(); + final List rules = []; rules.add(VineBooleanRule(includeLiteral, message)); return VineBooleanSchema(rules); } VineAny any() { - final Queue rules = Queue(); + final List rules = []; rules.add(VineAnyRule()); return VineAnySchema(rules); } VineEnum enumerate(List source) { - final Queue rules = Queue(); + final List rules = []; rules.add(VineEnumRule(source)); return VineEnumSchema(rules, source); } VineArray array(VineSchema schema) { - final Queue rules = Queue(); + final List rules = []; rules.add(VineArrayRule(schema)); return VineArraySchema(rules); } VineUnion union(List schemas) { - final Queue rules = Queue(); + final List rules = []; rules.add(VineUnionRule(schemas)); return VineUnionSchema(rules, schemas); } VineDate date({String? message}) { - final Queue rules = Queue(); + final List rules = []; rules.add(VineDateRule(message)); return VineDateSchema(rules); @@ -145,23 +143,7 @@ final class Validator implements VineValidatorContract { final validatorContext = VineValidatorContext(reporter, data); final field = VineField('', data); - // if (_schema case VineObjectSchema object) { - // for (final property in object.properties.entries) { - // if (property.value case VineNumberSchema number) { - // print(['initial', property.key, number.rules]); - // } - // } - // } - - // if (schema case VineObjectSchema object) { - // for (final property in object.properties.entries) { - // if (property.value case VineNumberSchema number) { - // print(['derived', property.key, number.rules]); - // } - // } - // } - - schema.parse(validatorContext, field); + _schema.parse(validatorContext, field); if (reporter.hasError) { throw reporter.createError({'errors': reporter.errors}); diff --git a/test/rules/number_test.dart b/test/rules/number_test.dart index 0e1ab78..ab17a26 100755 --- a/test/rules/number_test.dart +++ b/test/rules/number_test.dart @@ -302,7 +302,7 @@ void main() { throwsA(isA())); }); - test('indepedant test', () { + test('validate many times', () { final validator = vine.compile(vine.object({ 'toto': vine.number().min(18).optional(), })); @@ -316,6 +316,6 @@ void main() { 'toto': 17, }); }, throwsA(isA())); - }, tags: ['test']); + }); }); } diff --git a/test/test.test.dart b/test/test.test.dart deleted file mode 100644 index 25e3ed8..0000000 --- a/test/test.test.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:test/expect.dart'; -import 'package:test/scaffolding.dart'; -import 'package:vine/src/vine.dart'; - -import 'rules/enum_test.dart'; - -void main() { - test('test', () { - final validator = vine.compile( - vine.object({'value': vine.enumerate(MyEnum.values).optional()})); - - expect(() => validator.validate({}), returnsNormally); - }); -}