diff --git a/packages/luthor/lib/src/validations/numbers/max_validation.dart b/packages/luthor/lib/src/validations/numbers/max_validation.dart new file mode 100644 index 00000000..0e8b97c6 --- /dev/null +++ b/packages/luthor/lib/src/validations/numbers/max_validation.dart @@ -0,0 +1,30 @@ +import 'package:luthor/src/validation.dart'; + +class NumberMaxValidation extends Validation { + num maxValue; + String? customMessage; + + NumberMaxValidation({ + required this.maxValue, + String? message, + }) : customMessage = message; + + @override + bool call(String? fieldName, Object? value) { + super.call(fieldName, value); + + if (value == null) return true; + if (value is! num) return false; + + return value <= maxValue; + } + + @override + String get message { + if (customMessage != null) return customMessage!; + return '${fieldName ?? 'value'} must be less than or equal to $maxValue'; + } + + @override + Map>? get errors => null; +} diff --git a/packages/luthor/lib/src/validations/numbers/min_validation.dart b/packages/luthor/lib/src/validations/numbers/min_validation.dart new file mode 100644 index 00000000..7e9c3198 --- /dev/null +++ b/packages/luthor/lib/src/validations/numbers/min_validation.dart @@ -0,0 +1,30 @@ +import 'package:luthor/src/validation.dart'; + +class NumberMinValidation extends Validation { + num minValue; + String? customMessage; + + NumberMinValidation({ + required this.minValue, + String? message, + }) : customMessage = message; + + @override + bool call(String? fieldName, Object? value) { + super.call(fieldName, value); + + if (value == null) return true; + if (value is! num) return false; + + return value >= minValue; + } + + @override + String get message { + if (customMessage != null) return customMessage!; + return '${fieldName ?? 'value'} must be greater than or equal to $minValue'; + } + + @override + Map>? get errors => null; +} diff --git a/packages/luthor/lib/src/validator.dart b/packages/luthor/lib/src/validator.dart index f2d2cef8..50f6a65d 100644 --- a/packages/luthor/lib/src/validator.dart +++ b/packages/luthor/lib/src/validator.dart @@ -10,6 +10,9 @@ import 'package:luthor/src/validations/number_validation.dart'; import 'package:luthor/src/validations/required_validation.dart'; import 'package:luthor/src/validations/schema_validation.dart'; import 'package:luthor/src/validations/string_validation.dart'; +import 'package:luthor/src/validators/double_validator.dart'; +import 'package:luthor/src/validators/int_validator.dart'; +import 'package:luthor/src/validators/number_validator.dart'; import 'package:luthor/src/validators/string_validator.dart'; typedef FromJson = T Function(Map json); @@ -46,21 +49,21 @@ class Validator { } /// Validates that the value is a number (int or double). - Validator number({String? message}) { + NumberValidator number({String? message}) { validations.add(NumberValidation(message: message)); - return this; + return NumberValidator(initialValidations: validations); } /// Validates that the value is an int. - Validator int({String? message}) { + IntValidator int({String? message}) { validations.add(IntValidation(message: message)); - return this; + return IntValidator(initialValidations: validations); } /// Validates that the value is a double. - Validator double({String? message}) { + DoubleValidator double({String? message}) { validations.add(DoubleValidation(message: message)); - return this; + return DoubleValidator(initialValidations: validations); } /// Validates that the value is a bool. diff --git a/packages/luthor/lib/src/validators/double_validator.dart b/packages/luthor/lib/src/validators/double_validator.dart new file mode 100644 index 00000000..f77b8960 --- /dev/null +++ b/packages/luthor/lib/src/validators/double_validator.dart @@ -0,0 +1,20 @@ +import 'package:luthor/src/validations/numbers/max_validation.dart'; +import 'package:luthor/src/validations/numbers/min_validation.dart'; +import 'package:luthor/src/validator.dart'; + +/// Validator for ints. +class DoubleValidator extends Validator { + DoubleValidator({super.initialValidations}); + + /// Validates that the int is greater than or equal to minValue. + DoubleValidator min(double minValue, {String? message}) { + validations.add(NumberMinValidation(minValue: minValue, message: message)); + return this; + } + + /// Validates that the int is less than or equal to minValue. + DoubleValidator max(double maxValue, {String? message}) { + validations.add(NumberMaxValidation(maxValue: maxValue, message: message)); + return this; + } +} diff --git a/packages/luthor/lib/src/validators/int_validator.dart b/packages/luthor/lib/src/validators/int_validator.dart new file mode 100644 index 00000000..aaad164e --- /dev/null +++ b/packages/luthor/lib/src/validators/int_validator.dart @@ -0,0 +1,20 @@ +import 'package:luthor/src/validations/numbers/max_validation.dart'; +import 'package:luthor/src/validations/numbers/min_validation.dart'; +import 'package:luthor/src/validator.dart'; + +/// Validator for ints. +class IntValidator extends Validator { + IntValidator({super.initialValidations}); + + /// Validates that the int is greater than or equal to minValue. + IntValidator min(int minValue, {String? message}) { + validations.add(NumberMinValidation(minValue: minValue, message: message)); + return this; + } + + /// Validates that the int is less than or equal to minValue. + IntValidator max(int maxValue, {String? message}) { + validations.add(NumberMaxValidation(maxValue: maxValue, message: message)); + return this; + } +} diff --git a/packages/luthor/lib/src/validators/number_validator.dart b/packages/luthor/lib/src/validators/number_validator.dart new file mode 100644 index 00000000..2ba3d2bd --- /dev/null +++ b/packages/luthor/lib/src/validators/number_validator.dart @@ -0,0 +1,20 @@ +import 'package:luthor/src/validations/numbers/max_validation.dart'; +import 'package:luthor/src/validations/numbers/min_validation.dart'; +import 'package:luthor/src/validator.dart'; + +/// Validator for nums. +class NumberValidator extends Validator { + NumberValidator({super.initialValidations}); + + /// Validates that the int is greater than or equal to minValue. + NumberValidator min(num minValue, {String? message}) { + validations.add(NumberMinValidation(minValue: minValue, message: message)); + return this; + } + + /// Validates that the int is less than or equal to minValue. + NumberValidator max(num maxValue, {String? message}) { + validations.add(NumberMaxValidation(maxValue: maxValue, message: message)); + return this; + } +} diff --git a/packages/luthor/test/validations/doubles/double_max_validation_test.dart b/packages/luthor/test/validations/doubles/double_max_validation_test.dart new file mode 100644 index 00000000..6cd2d328 --- /dev/null +++ b/packages/luthor/test/validations/doubles/double_max_validation_test.dart @@ -0,0 +1,60 @@ +import 'package:luthor/luthor.dart'; +import 'package:test/test.dart'; + +void main() { + test( + 'should return true if the double is less than or equal to maxValue', + () { + final result = l.double().max(3.0).validateValue(2.0); + + switch (result) { + case SingleValidationSuccess(data: _): + expect(result.data, 2.0); + case SingleValidationError(data: _, errors: _): + fail('should not have errors'); + } + }, + ); + + test( + 'should return false if the double is greater than maxValue', + () { + final result = l.double().max(3.0).validateValue(4.0); + + switch (result) { + case SingleValidationSuccess(data: _): + fail('should not be a success'); + case SingleValidationError(data: _, errors: final errors): + expect(errors, ['value must be less than or equal to 3.0']); + } + }, + ); + + test( + 'should return true when the value is null', + () { + final result = l.double().max(3.0).validateValue(null); + + switch (result) { + case SingleValidationSuccess(data: _): + expect(result.data, isNull); + case SingleValidationError(data: _, errors: _): + fail('should not have errors'); + } + }, + ); + + test( + 'should return false if the value is null with required()', + () { + final result = l.double().max(3.0).required().validateValue(null); + + switch (result) { + case SingleValidationSuccess(data: _): + fail('should not be a success'); + case SingleValidationError(data: _, errors: final errors): + expect(errors, ['value is required']); + } + }, + ); +} diff --git a/packages/luthor/test/validations/doubles/double_min_validation_test.dart b/packages/luthor/test/validations/doubles/double_min_validation_test.dart new file mode 100644 index 00000000..1f53af89 --- /dev/null +++ b/packages/luthor/test/validations/doubles/double_min_validation_test.dart @@ -0,0 +1,60 @@ +import 'package:luthor/luthor.dart'; +import 'package:test/test.dart'; + +void main() { + test( + 'should return true if the double is greater than or equal to minValue', + () { + final result = l.double().min(3.0).validateValue(4.0); + + switch (result) { + case SingleValidationSuccess(data: _): + expect(result.data, 4.0); + case SingleValidationError(data: _, errors: _): + fail('should not have errors'); + } + }, + ); + + test( + 'should return false if the double is less than minValue', + () { + final result = l.double().min(3.0).validateValue(2.0); + + switch (result) { + case SingleValidationSuccess(data: _): + fail('should not be a success'); + case SingleValidationError(data: _, errors: final errors): + expect(errors, ['value must be greater than or equal to 3.0']); + } + }, + ); + + test( + 'should return true when the value is null', + () { + final result = l.double().min(3.0).validateValue(null); + + switch (result) { + case SingleValidationSuccess(data: _): + expect(result.data, isNull); + case SingleValidationError(data: _, errors: _): + fail('should not have errors'); + } + }, + ); + + test( + 'should return false if the value is null with required()', + () { + final result = l.double().min(3.0).required().validateValue(null); + + switch (result) { + case SingleValidationSuccess(data: _): + fail('should not be a success'); + case SingleValidationError(data: _, errors: final errors): + expect(errors, ['value is required']); + } + }, + ); +} diff --git a/packages/luthor/test/validations/ints/int_max_validation_test.dart b/packages/luthor/test/validations/ints/int_max_validation_test.dart new file mode 100644 index 00000000..e204e570 --- /dev/null +++ b/packages/luthor/test/validations/ints/int_max_validation_test.dart @@ -0,0 +1,60 @@ +import 'package:luthor/luthor.dart'; +import 'package:test/test.dart'; + +void main() { + test( + 'should return true if the int is less than or equal to maxValue', + () { + final result = l.int().max(3).validateValue(2); + + switch (result) { + case SingleValidationSuccess(data: _): + expect(result.data, 2); + case SingleValidationError(data: _, errors: _): + fail('should not have errors'); + } + }, + ); + + test( + 'should return false if the int is greater than maxValue', + () { + final result = l.int().max(3).validateValue(4); + + switch (result) { + case SingleValidationSuccess(data: _): + fail('should not be a success'); + case SingleValidationError(data: _, errors: final errors): + expect(errors, ['value must be less than or equal to 3']); + } + }, + ); + + test( + 'should return true when the value is null', + () { + final result = l.int().max(3).validateValue(null); + + switch (result) { + case SingleValidationSuccess(data: _): + expect(result.data, isNull); + case SingleValidationError(data: _, errors: _): + fail('should not have errors'); + } + }, + ); + + test( + 'should return false if the value is null with required()', + () { + final result = l.int().max(3).required().validateValue(null); + + switch (result) { + case SingleValidationSuccess(data: _): + fail('should not be a success'); + case SingleValidationError(data: _, errors: final errors): + expect(errors, ['value is required']); + } + }, + ); +} diff --git a/packages/luthor/test/validations/ints/int_min_validation_test.dart b/packages/luthor/test/validations/ints/int_min_validation_test.dart new file mode 100644 index 00000000..088ab89e --- /dev/null +++ b/packages/luthor/test/validations/ints/int_min_validation_test.dart @@ -0,0 +1,60 @@ +import 'package:luthor/luthor.dart'; +import 'package:test/test.dart'; + +void main() { + test( + 'should return true if the int is greater than or equal to minValue', + () { + final result = l.int().min(3).validateValue(4); + + switch (result) { + case SingleValidationSuccess(data: _): + expect(result.data, 4); + case SingleValidationError(data: _, errors: _): + fail('should not have errors'); + } + }, + ); + + test( + 'should return false if the int is less than minValue', + () { + final result = l.int().min(3).validateValue(2); + + switch (result) { + case SingleValidationSuccess(data: _): + fail('should not be a success'); + case SingleValidationError(data: _, errors: final errors): + expect(errors, ['value must be greater than or equal to 3']); + } + }, + ); + + test( + 'should return true when the value is null', + () { + final result = l.int().min(3).validateValue(null); + + switch (result) { + case SingleValidationSuccess(data: _): + expect(result.data, isNull); + case SingleValidationError(data: _, errors: _): + fail('should not have errors'); + } + }, + ); + + test( + 'should return false if the value is null with required()', + () { + final result = l.int().min(3).required().validateValue(null); + + switch (result) { + case SingleValidationSuccess(data: _): + fail('should not be a success'); + case SingleValidationError(data: _, errors: final errors): + expect(errors, ['value is required']); + } + }, + ); +} diff --git a/packages/luthor/test/validations/numbers/number_max_validation_test.dart b/packages/luthor/test/validations/numbers/number_max_validation_test.dart new file mode 100644 index 00000000..e70f949d --- /dev/null +++ b/packages/luthor/test/validations/numbers/number_max_validation_test.dart @@ -0,0 +1,60 @@ +import 'package:luthor/luthor.dart'; +import 'package:test/test.dart'; + +void main() { + test( + 'should return true if the num is less than or equal to maxValue', + () { + final result = l.number().max(3).validateValue(2); + + switch (result) { + case SingleValidationSuccess(data: _): + expect(result.data, 2); + case SingleValidationError(data: _, errors: _): + fail('should not have errors'); + } + }, + ); + + test( + 'should return false if the num is greater than maxValue', + () { + final result = l.number().max(3).validateValue(4); + + switch (result) { + case SingleValidationSuccess(data: _): + fail('should not be a success'); + case SingleValidationError(data: _, errors: final errors): + expect(errors, ['value must be less than or equal to 3']); + } + }, + ); + + test( + 'should return true when the value is null', + () { + final result = l.number().max(3).validateValue(null); + + switch (result) { + case SingleValidationSuccess(data: _): + expect(result.data, isNull); + case SingleValidationError(data: _, errors: _): + fail('should not have errors'); + } + }, + ); + + test( + 'should return false if the value is null with required()', + () { + final result = l.number().max(3).required().validateValue(null); + + switch (result) { + case SingleValidationSuccess(data: _): + fail('should not be a success'); + case SingleValidationError(data: _, errors: final errors): + expect(errors, ['value is required']); + } + }, + ); +} diff --git a/packages/luthor/test/validations/numbers/number_min_validation_test.dart b/packages/luthor/test/validations/numbers/number_min_validation_test.dart new file mode 100644 index 00000000..85679023 --- /dev/null +++ b/packages/luthor/test/validations/numbers/number_min_validation_test.dart @@ -0,0 +1,60 @@ +import 'package:luthor/luthor.dart'; +import 'package:test/test.dart'; + +void main() { + test( + 'should return true if the num is greater than or equal to minValue', + () { + final result = l.number().min(3).validateValue(4); + + switch (result) { + case SingleValidationSuccess(data: _): + expect(result.data, 4); + case SingleValidationError(data: _, errors: _): + fail('should not have errors'); + } + }, + ); + + test( + 'should return false if the num is less than minValue', + () { + final result = l.number().min(3).validateValue(2); + + switch (result) { + case SingleValidationSuccess(data: _): + fail('should not be a success'); + case SingleValidationError(data: _, errors: final errors): + expect(errors, ['value must be greater than or equal to 3']); + } + }, + ); + + test( + 'should return true when the value is null', + () { + final result = l.number().min(3).validateValue(null); + + switch (result) { + case SingleValidationSuccess(data: _): + expect(result.data, isNull); + case SingleValidationError(data: _, errors: _): + fail('should not have errors'); + } + }, + ); + + test( + 'should return false if the value is null with required()', + () { + final result = l.number().min(3).required().validateValue(null); + + switch (result) { + case SingleValidationSuccess(data: _): + fail('should not be a success'); + case SingleValidationError(data: _, errors: final errors): + expect(errors, ['value is required']); + } + }, + ); +} diff --git a/packages/luthor_annotation/lib/src/validators/max.dart b/packages/luthor_annotation/lib/src/validators/max.dart index ca4f9932..3e30bec2 100644 --- a/packages/luthor_annotation/lib/src/validators/max.dart +++ b/packages/luthor_annotation/lib/src/validators/max.dart @@ -4,3 +4,17 @@ class HasMax { const HasMax(this.max, {this.message}); } + +class HasMaxDouble { + final String? message; + final double max; + + const HasMaxDouble(this.max, {this.message}); +} + +class HasMaxNumber { + final String? message; + final num max; + + const HasMaxNumber(this.max, {this.message}); +} diff --git a/packages/luthor_annotation/lib/src/validators/min.dart b/packages/luthor_annotation/lib/src/validators/min.dart index e04d2012..f190b2b5 100644 --- a/packages/luthor_annotation/lib/src/validators/min.dart +++ b/packages/luthor_annotation/lib/src/validators/min.dart @@ -4,3 +4,17 @@ class HasMin { const HasMin(this.min, {this.message}); } + +class HasMinDouble { + final String? message; + final double min; + + const HasMinDouble(this.min, {this.message}); +} + +class HasMinNumber { + final String? message; + final num min; + + const HasMinNumber(this.min, {this.message}); +} diff --git a/packages/luthor_generator/example/lib/another_sample.freezed.dart b/packages/luthor_generator/example/lib/another_sample.freezed.dart index 9f3dd486..b56a8c6f 100644 --- a/packages/luthor_generator/example/lib/another_sample.freezed.dart +++ b/packages/luthor_generator/example/lib/another_sample.freezed.dart @@ -12,7 +12,7 @@ part of 'another_sample.dart'; T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); AnotherSample _$AnotherSampleFromJson(Map json) { return _AnotherSample.fromJson(json); @@ -168,7 +168,7 @@ class _$AnotherSampleImpl implements _AnotherSample { } @override - bool operator ==(dynamic other) { + bool operator ==(Object other) { return identical(this, other) || (other.runtimeType == runtimeType && other is _$AnotherSampleImpl && diff --git a/packages/luthor_generator/example/lib/sample.dart b/packages/luthor_generator/example/lib/sample.dart index e43ae2f8..fbccd661 100644 --- a/packages/luthor_generator/example/lib/sample.dart +++ b/packages/luthor_generator/example/lib/sample.dart @@ -26,7 +26,10 @@ class Sample with _$Sample { @isDateTime required String date, required DateTime dateTime, @HasLength(10) String? exactly10Characters, - @HasMin(8) @HasMax(200) required String minAndMax, + @HasMin(8) @HasMax(200) required String minAndMaxString, + @HasMin(2) @HasMax(4) required int minAndMaxInt, + @HasMinDouble(2.0) @HasMaxDouble(4.0) required double minAndMaxDouble, + @HasMinNumber(2) @HasMaxNumber(3.0) required num minAndMaxNumber, @IsUri(allowedSchemes: ['https']) String? httpsLink, @MatchRegex(r'^https:\/\/pub\.dev\/packages\/luthor') required String luthorPath, @@ -52,4 +55,38 @@ void main() { print('Success: $data'); data.validateSelf(); } + + print('*' * 10); + final result2 = Sample.validate({ + "minAndMaxInt": 1, + "minAndMaxDouble": 1.0, + "minAndMaxNumber": 1, + }); + switch (result2) { + case SchemaValidationError(errors: final errors): + print('Error: Result 2'); + errors.forEach((key, value) { + print('$key: $value'); + }); + case SchemaValidationSuccess(data: final data): + print('Success: $data'); + data.validateSelf(); + } + + print('*' * 10); + final result3 = Sample.validate({ + "minAndMaxInt": 5, + "minAndMaxDouble": 5.0, + "minAndMaxNumber": 5, + }); + switch (result3) { + case SchemaValidationError(errors: final errors): + print('Error: Result 3'); + errors.forEach((key, value) { + print('$key: $value'); + }); + case SchemaValidationSuccess(data: final data): + print('Success: $data'); + data.validateSelf(); + } } diff --git a/packages/luthor_generator/example/lib/sample.freezed.dart b/packages/luthor_generator/example/lib/sample.freezed.dart index 2c985d09..0ab09f60 100644 --- a/packages/luthor_generator/example/lib/sample.freezed.dart +++ b/packages/luthor_generator/example/lib/sample.freezed.dart @@ -12,7 +12,7 @@ part of 'sample.dart'; T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); Sample _$SampleFromJson(Map json) { return _Sample.fromJson(json); @@ -38,7 +38,16 @@ mixin _$Sample { String? get exactly10Characters => throw _privateConstructorUsedError; @HasMin(8) @HasMax(200) - String get minAndMax => throw _privateConstructorUsedError; + String get minAndMaxString => throw _privateConstructorUsedError; + @HasMin(2) + @HasMax(4) + int get minAndMaxInt => throw _privateConstructorUsedError; + @HasMinDouble(2.0) + @HasMaxDouble(4.0) + double get minAndMaxDouble => throw _privateConstructorUsedError; + @HasMinNumber(2) + @HasMaxNumber(3.0) + num get minAndMaxNumber => throw _privateConstructorUsedError; @IsUri(allowedSchemes: ['https']) String? get httpsLink => throw _privateConstructorUsedError; @MatchRegex(r'^https:\/\/pub\.dev\/packages\/luthor') @@ -69,7 +78,10 @@ abstract class $SampleCopyWith<$Res> { @isDateTime String date, DateTime dateTime, @HasLength(10) String? exactly10Characters, - @HasMin(8) @HasMax(200) String minAndMax, + @HasMin(8) @HasMax(200) String minAndMaxString, + @HasMin(2) @HasMax(4) int minAndMaxInt, + @HasMinDouble(2.0) @HasMaxDouble(4.0) double minAndMaxDouble, + @HasMinNumber(2) @HasMaxNumber(3.0) num minAndMaxNumber, @IsUri(allowedSchemes: ['https']) String? httpsLink, @MatchRegex(r'^https:\/\/pub\.dev\/packages\/luthor') String luthorPath, AnotherSample anotherSample, @@ -102,7 +114,10 @@ class _$SampleCopyWithImpl<$Res, $Val extends Sample> Object? date = null, Object? dateTime = null, Object? exactly10Characters = freezed, - Object? minAndMax = null, + Object? minAndMaxString = null, + Object? minAndMaxInt = null, + Object? minAndMaxDouble = null, + Object? minAndMaxNumber = null, Object? httpsLink = freezed, Object? luthorPath = null, Object? anotherSample = null, @@ -153,10 +168,22 @@ class _$SampleCopyWithImpl<$Res, $Val extends Sample> ? _value.exactly10Characters : exactly10Characters // ignore: cast_nullable_to_non_nullable as String?, - minAndMax: null == minAndMax - ? _value.minAndMax - : minAndMax // ignore: cast_nullable_to_non_nullable + minAndMaxString: null == minAndMaxString + ? _value.minAndMaxString + : minAndMaxString // ignore: cast_nullable_to_non_nullable as String, + minAndMaxInt: null == minAndMaxInt + ? _value.minAndMaxInt + : minAndMaxInt // ignore: cast_nullable_to_non_nullable + as int, + minAndMaxDouble: null == minAndMaxDouble + ? _value.minAndMaxDouble + : minAndMaxDouble // ignore: cast_nullable_to_non_nullable + as double, + minAndMaxNumber: null == minAndMaxNumber + ? _value.minAndMaxNumber + : minAndMaxNumber // ignore: cast_nullable_to_non_nullable + as num, httpsLink: freezed == httpsLink ? _value.httpsLink : httpsLink // ignore: cast_nullable_to_non_nullable @@ -204,7 +231,10 @@ abstract class _$$SampleImplCopyWith<$Res> implements $SampleCopyWith<$Res> { @isDateTime String date, DateTime dateTime, @HasLength(10) String? exactly10Characters, - @HasMin(8) @HasMax(200) String minAndMax, + @HasMin(8) @HasMax(200) String minAndMaxString, + @HasMin(2) @HasMax(4) int minAndMaxInt, + @HasMinDouble(2.0) @HasMaxDouble(4.0) double minAndMaxDouble, + @HasMinNumber(2) @HasMaxNumber(3.0) num minAndMaxNumber, @IsUri(allowedSchemes: ['https']) String? httpsLink, @MatchRegex(r'^https:\/\/pub\.dev\/packages\/luthor') String luthorPath, AnotherSample anotherSample, @@ -236,7 +266,10 @@ class __$$SampleImplCopyWithImpl<$Res> Object? date = null, Object? dateTime = null, Object? exactly10Characters = freezed, - Object? minAndMax = null, + Object? minAndMaxString = null, + Object? minAndMaxInt = null, + Object? minAndMaxDouble = null, + Object? minAndMaxNumber = null, Object? httpsLink = freezed, Object? luthorPath = null, Object? anotherSample = null, @@ -287,10 +320,22 @@ class __$$SampleImplCopyWithImpl<$Res> ? _value.exactly10Characters : exactly10Characters // ignore: cast_nullable_to_non_nullable as String?, - minAndMax: null == minAndMax - ? _value.minAndMax - : minAndMax // ignore: cast_nullable_to_non_nullable + minAndMaxString: null == minAndMaxString + ? _value.minAndMaxString + : minAndMaxString // ignore: cast_nullable_to_non_nullable as String, + minAndMaxInt: null == minAndMaxInt + ? _value.minAndMaxInt + : minAndMaxInt // ignore: cast_nullable_to_non_nullable + as int, + minAndMaxDouble: null == minAndMaxDouble + ? _value.minAndMaxDouble + : minAndMaxDouble // ignore: cast_nullable_to_non_nullable + as double, + minAndMaxNumber: null == minAndMaxNumber + ? _value.minAndMaxNumber + : minAndMaxNumber // ignore: cast_nullable_to_non_nullable + as num, httpsLink: freezed == httpsLink ? _value.httpsLink : httpsLink // ignore: cast_nullable_to_non_nullable @@ -326,7 +371,10 @@ class _$SampleImpl implements _Sample { @isDateTime required this.date, required this.dateTime, @HasLength(10) this.exactly10Characters, - @HasMin(8) @HasMax(200) required this.minAndMax, + @HasMin(8) @HasMax(200) required this.minAndMaxString, + @HasMin(2) @HasMax(4) required this.minAndMaxInt, + @HasMinDouble(2.0) @HasMaxDouble(4.0) required this.minAndMaxDouble, + @HasMinNumber(2) @HasMaxNumber(3.0) required this.minAndMaxNumber, @IsUri(allowedSchemes: ['https']) this.httpsLink, @MatchRegex(r'^https:\/\/pub\.dev\/packages\/luthor') required this.luthorPath, @@ -373,7 +421,19 @@ class _$SampleImpl implements _Sample { @override @HasMin(8) @HasMax(200) - final String minAndMax; + final String minAndMaxString; + @override + @HasMin(2) + @HasMax(4) + final int minAndMaxInt; + @override + @HasMinDouble(2.0) + @HasMaxDouble(4.0) + final double minAndMaxDouble; + @override + @HasMinNumber(2) + @HasMaxNumber(3.0) + final num minAndMaxNumber; @override @IsUri(allowedSchemes: ['https']) final String? httpsLink; @@ -388,11 +448,11 @@ class _$SampleImpl implements _Sample { @override String toString() { - return 'Sample(anyValue: $anyValue, boolValue: $boolValue, doubleValue: $doubleValue, intValue: $intValue, listValue: $listValue, numValue: $numValue, stringValue: $stringValue, email: $email, date: $date, dateTime: $dateTime, exactly10Characters: $exactly10Characters, minAndMax: $minAndMax, httpsLink: $httpsLink, luthorPath: $luthorPath, anotherSample: $anotherSample, foo: $foo)'; + return 'Sample(anyValue: $anyValue, boolValue: $boolValue, doubleValue: $doubleValue, intValue: $intValue, listValue: $listValue, numValue: $numValue, stringValue: $stringValue, email: $email, date: $date, dateTime: $dateTime, exactly10Characters: $exactly10Characters, minAndMaxString: $minAndMaxString, minAndMaxInt: $minAndMaxInt, minAndMaxDouble: $minAndMaxDouble, minAndMaxNumber: $minAndMaxNumber, httpsLink: $httpsLink, luthorPath: $luthorPath, anotherSample: $anotherSample, foo: $foo)'; } @override - bool operator ==(dynamic other) { + bool operator ==(Object other) { return identical(this, other) || (other.runtimeType == runtimeType && other is _$SampleImpl && @@ -415,8 +475,14 @@ class _$SampleImpl implements _Sample { other.dateTime == dateTime) && (identical(other.exactly10Characters, exactly10Characters) || other.exactly10Characters == exactly10Characters) && - (identical(other.minAndMax, minAndMax) || - other.minAndMax == minAndMax) && + (identical(other.minAndMaxString, minAndMaxString) || + other.minAndMaxString == minAndMaxString) && + (identical(other.minAndMaxInt, minAndMaxInt) || + other.minAndMaxInt == minAndMaxInt) && + (identical(other.minAndMaxDouble, minAndMaxDouble) || + other.minAndMaxDouble == minAndMaxDouble) && + (identical(other.minAndMaxNumber, minAndMaxNumber) || + other.minAndMaxNumber == minAndMaxNumber) && (identical(other.httpsLink, httpsLink) || other.httpsLink == httpsLink) && (identical(other.luthorPath, luthorPath) || @@ -428,24 +494,28 @@ class _$SampleImpl implements _Sample { @JsonKey(ignore: true) @override - int get hashCode => Object.hash( - runtimeType, - const DeepCollectionEquality().hash(anyValue), - boolValue, - doubleValue, - intValue, - const DeepCollectionEquality().hash(_listValue), - numValue, - stringValue, - email, - date, - dateTime, - exactly10Characters, - minAndMax, - httpsLink, - luthorPath, - anotherSample, - foo); + int get hashCode => Object.hashAll([ + runtimeType, + const DeepCollectionEquality().hash(anyValue), + boolValue, + doubleValue, + intValue, + const DeepCollectionEquality().hash(_listValue), + numValue, + stringValue, + email, + date, + dateTime, + exactly10Characters, + minAndMaxString, + minAndMaxInt, + minAndMaxDouble, + minAndMaxNumber, + httpsLink, + luthorPath, + anotherSample, + foo + ]); @JsonKey(ignore: true) @override @@ -474,7 +544,12 @@ abstract class _Sample implements Sample { @isDateTime required final String date, required final DateTime dateTime, @HasLength(10) final String? exactly10Characters, - @HasMin(8) @HasMax(200) required final String minAndMax, + @HasMin(8) @HasMax(200) required final String minAndMaxString, + @HasMin(2) @HasMax(4) required final int minAndMaxInt, + @HasMinDouble(2.0) + @HasMaxDouble(4.0) + required final double minAndMaxDouble, + @HasMinNumber(2) @HasMaxNumber(3.0) required final num minAndMaxNumber, @IsUri(allowedSchemes: ['https']) final String? httpsLink, @MatchRegex(r'^https:\/\/pub\.dev\/packages\/luthor') required final String luthorPath, @@ -512,7 +587,19 @@ abstract class _Sample implements Sample { @override @HasMin(8) @HasMax(200) - String get minAndMax; + String get minAndMaxString; + @override + @HasMin(2) + @HasMax(4) + int get minAndMaxInt; + @override + @HasMinDouble(2.0) + @HasMaxDouble(4.0) + double get minAndMaxDouble; + @override + @HasMinNumber(2) + @HasMaxNumber(3.0) + num get minAndMaxNumber; @override @IsUri(allowedSchemes: ['https']) String? get httpsLink; diff --git a/packages/luthor_generator/example/lib/sample.g.dart b/packages/luthor_generator/example/lib/sample.g.dart index 19f02938..f4b3aa4e 100644 --- a/packages/luthor_generator/example/lib/sample.g.dart +++ b/packages/luthor_generator/example/lib/sample.g.dart @@ -19,7 +19,10 @@ _$SampleImpl _$$SampleImplFromJson(Map json) => _$SampleImpl( date: json['date'] as String, dateTime: DateTime.parse(json['dateTime'] as String), exactly10Characters: json['exactly10Characters'] as String?, - minAndMax: json['minAndMax'] as String, + minAndMaxString: json['minAndMaxString'] as String, + minAndMaxInt: json['minAndMaxInt'] as int, + minAndMaxDouble: (json['minAndMaxDouble'] as num).toDouble(), + minAndMaxNumber: json['minAndMaxNumber'] as num, httpsLink: json['httpsLink'] as String?, luthorPath: json['luthorPath'] as String, anotherSample: @@ -40,7 +43,10 @@ Map _$$SampleImplToJson(_$SampleImpl instance) => 'date': instance.date, 'dateTime': instance.dateTime.toIso8601String(), 'exactly10Characters': instance.exactly10Characters, - 'minAndMax': instance.minAndMax, + 'minAndMaxString': instance.minAndMaxString, + 'minAndMaxInt': instance.minAndMaxInt, + 'minAndMaxDouble': instance.minAndMaxDouble, + 'minAndMaxNumber': instance.minAndMaxNumber, 'httpsLink': instance.httpsLink, 'luthorPath': instance.luthorPath, 'anotherSample': instance.anotherSample, @@ -63,7 +69,10 @@ Validator $SampleSchema = l.schema({ 'date': l.string().dateTime().required(), 'dateTime': l.string().dateTime().required(), 'exactly10Characters': l.string().length(10), - 'minAndMax': l.string().max(200).min(8).required(), + 'minAndMaxString': l.string().max(200).min(8).required(), + 'minAndMaxInt': l.int().max(4).min(2).required(), + 'minAndMaxDouble': l.double().max(4.0).min(2.0).required(), + 'minAndMaxNumber': l.number().max(3.0).min(2).required(), 'httpsLink': l.string().uri(allowedSchemes: ['https']), 'luthorPath': l.string().regex(r"^https:\/\/pub\.dev\/packages\/luthor").required(), diff --git a/packages/luthor_generator/lib/checkers.dart b/packages/luthor_generator/lib/checkers.dart index 69c6686f..923c7db4 100644 --- a/packages/luthor_generator/lib/checkers.dart +++ b/packages/luthor_generator/lib/checkers.dart @@ -10,5 +10,9 @@ const isDateTimeChecker = TypeChecker.fromRuntime(IsDateTime); const hasLengthChecker = TypeChecker.fromRuntime(HasLength); const hasMaxChecker = TypeChecker.fromRuntime(HasMax); const hasMinChecker = TypeChecker.fromRuntime(HasMin); +const hasMaxDoubleChecker = TypeChecker.fromRuntime(HasMaxDouble); +const hasMinDoubleChecker = TypeChecker.fromRuntime(HasMinDouble); +const hasMaxNumberChecker = TypeChecker.fromRuntime(HasMaxNumber); +const hasMinNumberChecker = TypeChecker.fromRuntime(HasMinNumber); const isUriChecker = TypeChecker.fromRuntime(IsUri); const matchRegexChecker = TypeChecker.fromRuntime(MatchRegex); diff --git a/packages/luthor_generator/lib/helpers/validations/base_validations.dart b/packages/luthor_generator/lib/helpers/validations/base_validations.dart index 34576d02..b6375c72 100644 --- a/packages/luthor_generator/lib/helpers/validations/base_validations.dart +++ b/packages/luthor_generator/lib/helpers/validations/base_validations.dart @@ -4,6 +4,9 @@ import 'package:analyzer/dart/element/nullability_suffix.dart'; import 'package:analyzer/dart/element/type.dart'; import 'package:luthor_generator/checkers.dart'; import 'package:luthor_generator/errors/unsupported_type_error.dart'; +import 'package:luthor_generator/helpers/validations/double_validations.dart'; +import 'package:luthor_generator/helpers/validations/int_validations.dart'; +import 'package:luthor_generator/helpers/validations/number_validations.dart'; import 'package:luthor_generator/helpers/validations/string_validations.dart'; import 'package:source_gen/source_gen.dart'; @@ -22,10 +25,12 @@ String getValidations(ParameterElement param) { if (param.type.isDartCoreDouble) { buffer.write('l.double()'); + buffer.write(getDoubleValidations(param)); } if (param.type.isDartCoreInt) { buffer.write('l.int()'); + buffer.write(getIntValidations(param)); } if (param.type.isDartCoreList) { @@ -38,6 +43,7 @@ String getValidations(ParameterElement param) { if (param.type.isDartCoreNum) { buffer.write('l.number()'); + buffer.write(getNumberValidations(param)); } if (param.type.isDartCoreString || diff --git a/packages/luthor_generator/lib/helpers/validations/double_validations.dart b/packages/luthor_generator/lib/helpers/validations/double_validations.dart new file mode 100644 index 00000000..bc0cffaa --- /dev/null +++ b/packages/luthor_generator/lib/helpers/validations/double_validations.dart @@ -0,0 +1,42 @@ +import 'package:analyzer/dart/element/element.dart'; +import 'package:luthor_generator/checkers.dart'; +import 'package:luthor_generator/helpers/validations/base_validations.dart'; + +String getDoubleValidations(ParameterElement param) { + final buffer = StringBuffer(); + + _checkAndWriteMaxValidation(buffer, param); + _checkAndWriteMinValidation(buffer, param); + + return buffer.toString(); +} + +void _checkAndWriteMaxValidation( + StringBuffer buffer, + ParameterElement param, +) { + final maxAnnotation = getAnnotation(hasMaxDoubleChecker, param); + if (maxAnnotation != null) { + buffer.write('.max('); + final message = maxAnnotation.getField('message')?.toStringValue(); + final max = maxAnnotation.getField('max')!.toDoubleValue()!; + buffer.write(max); + if (message != null) buffer.write(", message: '$message'"); + buffer.write(')'); + } +} + +void _checkAndWriteMinValidation( + StringBuffer buffer, + ParameterElement param, +) { + final minAnnotation = getAnnotation(hasMinDoubleChecker, param); + if (minAnnotation != null) { + buffer.write('.min('); + final message = minAnnotation.getField('message')?.toStringValue(); + final min = minAnnotation.getField('min')!.toDoubleValue()!; + buffer.write(min); + if (message != null) buffer.write(", message: '$message'"); + buffer.write(')'); + } +} diff --git a/packages/luthor_generator/lib/helpers/validations/int_validations.dart b/packages/luthor_generator/lib/helpers/validations/int_validations.dart new file mode 100644 index 00000000..02ba7954 --- /dev/null +++ b/packages/luthor_generator/lib/helpers/validations/int_validations.dart @@ -0,0 +1,42 @@ +import 'package:analyzer/dart/element/element.dart'; +import 'package:luthor_generator/checkers.dart'; +import 'package:luthor_generator/helpers/validations/base_validations.dart'; + +String getIntValidations(ParameterElement param) { + final buffer = StringBuffer(); + + _checkAndWriteMaxValidation(buffer, param); + _checkAndWriteMinValidation(buffer, param); + + return buffer.toString(); +} + +void _checkAndWriteMaxValidation( + StringBuffer buffer, + ParameterElement param, +) { + final maxAnnotation = getAnnotation(hasMaxChecker, param); + if (maxAnnotation != null) { + buffer.write('.max('); + final message = maxAnnotation.getField('message')?.toStringValue(); + final max = maxAnnotation.getField('max')!.toIntValue()!; + buffer.write(max); + if (message != null) buffer.write(", message: '$message'"); + buffer.write(')'); + } +} + +void _checkAndWriteMinValidation( + StringBuffer buffer, + ParameterElement param, +) { + final minAnnotation = getAnnotation(hasMinChecker, param); + if (minAnnotation != null) { + buffer.write('.min('); + final message = minAnnotation.getField('message')?.toStringValue(); + final min = minAnnotation.getField('min')!.toIntValue()!; + buffer.write(min); + if (message != null) buffer.write(", message: '$message'"); + buffer.write(')'); + } +} diff --git a/packages/luthor_generator/lib/helpers/validations/number_validations.dart b/packages/luthor_generator/lib/helpers/validations/number_validations.dart new file mode 100644 index 00000000..de32aefe --- /dev/null +++ b/packages/luthor_generator/lib/helpers/validations/number_validations.dart @@ -0,0 +1,44 @@ +import 'package:analyzer/dart/element/element.dart'; +import 'package:luthor_generator/checkers.dart'; +import 'package:luthor_generator/helpers/validations/base_validations.dart'; + +String getNumberValidations(ParameterElement param) { + final buffer = StringBuffer(); + + _checkAndWriteMaxValidation(buffer, param); + _checkAndWriteMinValidation(buffer, param); + + return buffer.toString(); +} + +void _checkAndWriteMaxValidation( + StringBuffer buffer, + ParameterElement param, +) { + final maxAnnotation = getAnnotation(hasMaxNumberChecker, param); + if (maxAnnotation != null) { + buffer.write('.max('); + final message = maxAnnotation.getField('message')?.toStringValue(); + final maxInt = maxAnnotation.getField('max')!.toIntValue(); + final maxDouble = maxAnnotation.getField('max')!.toDoubleValue(); + buffer.write(maxInt ?? maxDouble); + if (message != null) buffer.write(", message: '$message'"); + buffer.write(')'); + } +} + +void _checkAndWriteMinValidation( + StringBuffer buffer, + ParameterElement param, +) { + final minAnnotation = getAnnotation(hasMinNumberChecker, param); + if (minAnnotation != null) { + buffer.write('.min('); + final message = minAnnotation.getField('message')?.toStringValue(); + final minInt = minAnnotation.getField('min')!.toIntValue(); + final minDouble = minAnnotation.getField('min')!.toDoubleValue(); + buffer.write(minInt ?? minDouble); + if (message != null) buffer.write(", message: '$message'"); + buffer.write(')'); + } +}