{"name":"EasyValidate","version":"1.0.0","description":"A modern, type-safe .NET validation library using source generators, Roslyn analyzers, and code fixers. EasyValidate enables powerful, composable, and type-safe validation using attributes with compile-time code generation and feedback.","repository":"https://github.com/mu-dawood/EasyValidate","documentation":"https://easy-validate.netlify.app","installation":{"nuget":"EasyValidate","dotnetCli":"dotnet add package EasyValidate"},"quickStart":{"steps":["1. Install the NuGet package: dotnet add package EasyValidate","2. Add using statements: using EasyValidate.Abstractions; using EasyValidate.Attributes;","3. Create a partial class implementing IGenerate interface","4. Add validation attributes to properties","5. Call the generated Validate() or ValidateAsync() method"],"example":"using EasyValidate.Abstractions;\nusing EasyValidate.Attributes;\n\n// Class MUST be partial and implement IGenerate\npublic partial class User : IGenerate\n{\n    [NotNull]\n    [NotEmpty]\n    public string? Name { get; set; }\n\n    [NotNull]\n    [EmailAddress]\n    public string? Email { get; set; }\n\n    [Range(18, 120)]\n    public int Age { get; set; }\n}\n\n// Usage\nvar user = new User { Name = \"John\", Email = \"john@example.com\", Age = 25 };\nvar result = user.Validate();\n\nif (result.IsValid())\n{\n    Console.WriteLine(\"Validation passed!\");\n}\nelse\n{\n    foreach (var prop in result.Results)\n    {\n        foreach (var chain in prop.Results)\n        {\n            foreach (var error in chain.Errors)\n            {\n                Console.WriteLine(error.FormattedMessage);\n            }\n        }\n    }\n}"},"coreInterfaces":[{"name":"IGenerate","description":"Marker interface that must be implemented by classes using EasyValidate validation. The source generator looks for this interface to generate the Validate() method.","usage":"public partial class MyClass : IGenerate { }"},{"name":"IValidationAttribute<TInput>","description":"Interface for synchronous validation attributes that validate a value without transformation.","usage":"Implement this interface in custom attributes with: AttributeResult Validate(string propertyName, TInput value);"},{"name":"IValidationAttribute<TInput, TOutput>","description":"Interface for synchronous validation attributes that validate and potentially transform a value.","usage":"Implement this interface for attributes that transform values during validation."},{"name":"IAsyncValidationAttribute<TInput>","description":"Interface for asynchronous validation attributes that need to call external services or databases.","usage":"Implement this interface with: Task<AttributeResult> ValidateAsync(string propertyName, TInput value);"},{"name":"IValidationResult","description":"Interface representing the result of validation with methods like IsValid(), HasErrors(), and access to Results collection.","usage":"var result = model.Validate(); if (result.IsValid()) { ... }"}],"attributes":[{"category":"String","description":"Attributes for validating string values including format, content, and pattern matching.","attributes":[{"name":"NotEmpty","description":"Validates that a string is not null, empty, or whitespace.","supportedTypes":["string"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[NotEmpty]\npublic string? Name { get; set; }","errorCode":"NotEmptyValidationError"},{"name":"EmailAddress","description":"Validates that a string is a valid email address format.","supportedTypes":["string"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[EmailAddress]\npublic string? Email { get; set; }","errorCode":"EmailAddressValidationError"},{"name":"Url","description":"Validates that a string is a valid URL.","supportedTypes":["string"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[Url]\npublic string? Website { get; set; }","errorCode":"UrlValidationError"},{"name":"Phone","description":"Validates that a string is a valid phone number (basic international/US format).","supportedTypes":["string"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[Phone]\npublic string? PhoneNumber { get; set; }","errorCode":"PhoneValidationError"},{"name":"CreditCard","description":"Validates that a string is a valid credit card number using Luhn algorithm.","supportedTypes":["string"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[CreditCard]\npublic string? CardNumber { get; set; }","errorCode":"CreditCardValidationError"},{"name":"Alpha","description":"Validates that a string contains only alphabetic characters (A-Z, a-z).","supportedTypes":["string"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[Alpha]\npublic string? FirstName { get; set; }","errorCode":"AlphaValidationError"},{"name":"AlphaNumeric","description":"Validates that a string contains only alphanumeric characters (A-Z, a-z, 0-9).","supportedTypes":["string"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[AlphaNumeric]\npublic string? Username { get; set; }","errorCode":"AlphaNumericValidationError"},{"name":"Numeric","description":"Validates that a string can be parsed as a number.","supportedTypes":["string"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[Numeric]\npublic string? Amount { get; set; }","errorCode":"NumericValidationError"},{"name":"Matches","description":"Validates that a string matches the specified regular expression pattern.","supportedTypes":["string"],"constructorParams":[{"name":"pattern","type":"string","description":"The regex pattern to match","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[Matches(@\"^[A-Z]{3}-\\d{4}$\")]\npublic string? ProductCode { get; set; }","errorCode":"MatchesValidationError"},{"name":"StartsWith","description":"Validates that a string starts with the specified prefix.","supportedTypes":["string"],"constructorParams":[{"name":"prefix","type":"string","description":"The prefix the string must start with","required":true},{"name":"comparison","type":"StringComparison","description":"The comparison type","required":false,"defaultValue":"Ordinal"}],"properties":["ErrorCode","Chain","ConditionalMethod","Comparison"],"example":"[StartsWith(\"https://\")]\npublic string? SecureUrl { get; set; }","errorCode":"StartsWithValidationError"},{"name":"EndsWith","description":"Validates that a string ends with the specified suffix.","supportedTypes":["string"],"constructorParams":[{"name":"suffix","type":"string","description":"The suffix the string must end with","required":true},{"name":"comparison","type":"StringComparison","description":"The comparison type","required":false,"defaultValue":"Ordinal"}],"properties":["ErrorCode","Chain","ConditionalMethod","Comparison"],"example":"[EndsWith(\".pdf\")]\npublic string? DocumentPath { get; set; }","errorCode":"EndsWithValidationError"},{"name":"Contains","description":"Validates that a string contains a specific substring.","supportedTypes":["string"],"constructorParams":[{"name":"substring","type":"string","description":"The substring that must be present","required":true},{"name":"comparison","type":"StringComparison","description":"The comparison type","required":false,"defaultValue":"Ordinal"}],"properties":["ErrorCode","Chain","ConditionalMethod","Comparison"],"example":"[Contains(\"@\")]\npublic string? Email { get; set; }","errorCode":"ContainsValidationError"},{"name":"NotContains","description":"Validates that a string does not contain a specific substring.","supportedTypes":["string"],"constructorParams":[{"name":"substring","type":"string","description":"The substring that must not be present","required":true},{"name":"comparison","type":"StringComparison","description":"The comparison type","required":false,"defaultValue":"Ordinal"}],"properties":["ErrorCode","Chain","ConditionalMethod","Comparison"],"example":"[NotContains(\"admin\")]\npublic string? Username { get; set; }","errorCode":"NotContainsValidationError"},{"name":"OneOf","description":"Validates that a string is one of the specified allowed values.","supportedTypes":["string"],"constructorParams":[{"name":"values","type":"params string[]","description":"The allowed values","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[OneOf(\"small\", \"medium\", \"large\")]\npublic string? Size { get; set; }","errorCode":"OneOfValidationError"},{"name":"NotOneOf","description":"Validates that a string is not one of the specified forbidden values.","supportedTypes":["string"],"constructorParams":[{"name":"values","type":"params string[]","description":"The forbidden values","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[NotOneOf(\"admin\", \"root\", \"system\")]\npublic string? Username { get; set; }","errorCode":"NotOneOfValidationError"},{"name":"Uppercase","description":"Validates that a string is all uppercase.","supportedTypes":["string"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[Uppercase]\npublic string? CountryCode { get; set; }","errorCode":"UppercaseValidationError"},{"name":"Lowercase","description":"Validates that a string is all lowercase.","supportedTypes":["string"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[Lowercase]\npublic string? Username { get; set; }","errorCode":"LowercaseValidationError"},{"name":"FirstLetterUpper","description":"Validates that the first letter of a string is uppercase.","supportedTypes":["string"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[FirstLetterUpper]\npublic string? Name { get; set; }","errorCode":"FirstLetterUpperValidationError"},{"name":"NoWhitespace","description":"Validates that a string does not contain any whitespace.","supportedTypes":["string"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[NoWhitespace]\npublic string? ApiKey { get; set; }","errorCode":"NoWhitespaceValidationError"},{"name":"Guid","description":"Validates that a string is a valid GUID format.","supportedTypes":["string"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[Guid]\npublic string? UserId { get; set; }","errorCode":"GuidValidationError"},{"name":"Hex","description":"Validates that a string contains only hexadecimal characters (0-9, a-f, A-F).","supportedTypes":["string"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[Hex]\npublic string? ColorCode { get; set; }","errorCode":"HexValidationError"},{"name":"Color","description":"Validates that a string is a valid color in hexadecimal format.","supportedTypes":["string"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[Color]\npublic string? BackgroundColor { get; set; }","errorCode":"ColorValidationError"},{"name":"IpAddress","description":"Validates that a string is a valid IPv4 or IPv6 address.","supportedTypes":["string"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[IpAddress]\npublic string? ServerIp { get; set; }","errorCode":"IpAddressValidationError"},{"name":"MacAddress","description":"Validates that a string is a valid MAC address.","supportedTypes":["string"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[MacAddress]\npublic string? DeviceId { get; set; }","errorCode":"MacAddressValidationError"},{"name":"ISBN","description":"Validates that a string is a valid ISBN-10 or ISBN-13.","supportedTypes":["string"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[ISBN]\npublic string? BookCode { get; set; }","errorCode":"ISBNValidationError"},{"name":"Ascii","description":"Validates that a string contains only ASCII characters (0x00-0x7F).","supportedTypes":["string"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[Ascii]\npublic string? Code { get; set; }","errorCode":"AsciiValidationError"},{"name":"CommonPrintable","description":"Validates that a string contains only common printable characters.","supportedTypes":["string"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[CommonPrintable]\npublic string? DisplayName { get; set; }","errorCode":"CommonPrintableValidationError"},{"name":"BaseEncoding","description":"Validates that a string is a valid Base16, Base32, Base58, Base62, Base64, or Base85 encoded value.","supportedTypes":["string"],"constructorParams":[{"name":"encoding","type":"BaseEncodingType","description":"The base encoding type to validate","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[BaseEncoding(BaseEncodingType.Base64)]\npublic string? EncodedData { get; set; }","errorCode":"BaseEncodingValidationError"},{"name":"FileExtension","description":"Validates that a string has a specific file extension.","supportedTypes":["string"],"constructorParams":[{"name":"extensions","type":"params string[]","description":"Allowed file extensions","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[FileExtension(\".jpg\", \".png\", \".gif\")]\npublic string? ImagePath { get; set; }","errorCode":"FileExtensionValidationError"},{"name":"ValidEnum","description":"Validates that a string matches a valid enum value.","supportedTypes":["string"],"constructorParams":[{"name":"enumType","type":"Type","description":"The enum type to validate against","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[ValidEnum(typeof(UserStatus))]\npublic string? Status { get; set; }","errorCode":"ValidEnumValidationError"}]},{"category":"Numeric","description":"Attributes for validating numeric values including ranges, comparisons, and mathematical properties.","attributes":[{"name":"Range","description":"Validates that a numeric value is within a specified range with configurable boundary inclusivity.","supportedTypes":["byte","sbyte","short","ushort","int","uint","long","ulong","float","double","decimal"],"constructorParams":[{"name":"minimum","type":"double/decimal/int","description":"The minimum value","required":true},{"name":"maximum","type":"double/decimal/int","description":"The maximum value","required":true},{"name":"boundary","type":"RangeBoundary","description":"Boundary inclusivity type","required":false,"defaultValue":"Inclusive"}],"properties":["ErrorCode","Chain","ConditionalMethod","Boundary"],"example":"[Range(18, 120)]\npublic int Age { get; set; }","errorCode":"RangeValidationError"},{"name":"Positive","description":"Validates that a numeric value is positive (greater than zero).","supportedTypes":["byte","sbyte","short","ushort","int","uint","long","ulong","float","double","decimal"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[Positive]\npublic decimal Price { get; set; }","errorCode":"PositiveValidationError"},{"name":"Negative","description":"Validates that a numeric value is negative (less than zero).","supportedTypes":["sbyte","short","int","long","float","double","decimal"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[Negative]\npublic int Deficit { get; set; }","errorCode":"NegativeValidationError"},{"name":"NonZero","description":"Validates that a numeric value is not zero.","supportedTypes":["byte","sbyte","short","ushort","int","uint","long","ulong","float","double","decimal"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[NonZero]\npublic int Divisor { get; set; }","errorCode":"NonZeroValidationError"},{"name":"GreaterThan","description":"Validates that a numeric value is greater than a specified comparison value.","supportedTypes":["byte","sbyte","short","ushort","int","uint","long","ulong","float","double","decimal"],"constructorParams":[{"name":"value","type":"double/decimal/int","description":"The value to compare against","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[GreaterThan(0)]\npublic int Quantity { get; set; }","errorCode":"GreaterThanValidationError"},{"name":"GreaterThanOrEqualTo","description":"Validates that a numeric value is greater than or equal to a specified comparison value.","supportedTypes":["byte","sbyte","short","ushort","int","uint","long","ulong","float","double","decimal"],"constructorParams":[{"name":"value","type":"double/decimal/int","description":"The value to compare against","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[GreaterThanOrEqualTo(18)]\npublic int Age { get; set; }","errorCode":"GreaterThanOrEqualToValidationError"},{"name":"LessThan","description":"Validates that a numeric value is less than a specified comparison value.","supportedTypes":["byte","sbyte","short","ushort","int","uint","long","ulong","float","double","decimal"],"constructorParams":[{"name":"value","type":"double/decimal/int","description":"The value to compare against","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[LessThan(100)]\npublic int Percentage { get; set; }","errorCode":"LessThanValidationError"},{"name":"LessThanOrEqualTo","description":"Validates that a numeric value is less than or equal to a specified comparison value.","supportedTypes":["byte","sbyte","short","ushort","int","uint","long","ulong","float","double","decimal"],"constructorParams":[{"name":"value","type":"double/decimal/int","description":"The value to compare against","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[LessThanOrEqualTo(100)]\npublic int Percentage { get; set; }","errorCode":"LessThanOrEqualToValidationError"},{"name":"DivisibleBy","description":"Validates that a numeric value is divisible by a specified number.","supportedTypes":["byte","sbyte","short","ushort","int","uint","long","ulong"],"constructorParams":[{"name":"divisor","type":"int/long","description":"The divisor (cannot be zero)","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[DivisibleBy(5)]\npublic int Quantity { get; set; }","errorCode":"DivisibleByValidationError"},{"name":"MultipleOf","description":"Validates that a numeric value is a multiple of a specified number.","supportedTypes":["byte","sbyte","short","ushort","int","uint","long","ulong","float","double","decimal"],"constructorParams":[{"name":"value","type":"double/decimal/int","description":"The value that the number must be a multiple of","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[MultipleOf(0.25)]\npublic decimal Price { get; set; }","errorCode":"MultipleOfValidationError"},{"name":"EvenNumber","description":"Validates that a numeric value is even.","supportedTypes":["byte","sbyte","short","ushort","int","uint","long","ulong"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[EvenNumber]\npublic int PlayerCount { get; set; }","errorCode":"EvenNumberValidationError"},{"name":"OddNumber","description":"Validates that a numeric value is odd.","supportedTypes":["byte","sbyte","short","ushort","int","uint","long","ulong"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[OddNumber]\npublic int LuckyNumber { get; set; }","errorCode":"OddNumberValidationError"},{"name":"Prime","description":"Validates that a numeric value is a prime number.","supportedTypes":["byte","sbyte","short","ushort","int","uint","long","ulong"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[Prime]\npublic int KeyValue { get; set; }","errorCode":"PrimeValidationError"},{"name":"Fibonacci","description":"Validates that a numeric value is a Fibonacci number.","supportedTypes":["byte","sbyte","short","ushort","int","uint","long","ulong"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[Fibonacci]\npublic int SpecialNumber { get; set; }","errorCode":"FibonacciValidationError"},{"name":"PowerOf","description":"Validates that a numeric value is a power of a specified base.","supportedTypes":["byte","sbyte","short","ushort","int","uint","long","ulong"],"constructorParams":[{"name":"base","type":"int","description":"The base value (must be greater than 1)","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[PowerOf(2)]\npublic int BufferSize { get; set; }","errorCode":"PowerOfValidationError"},{"name":"MinDigits","description":"Validates that an integer value has at least a specified number of digits.","supportedTypes":["int","uint","long","ulong"],"constructorParams":[{"name":"minDigits","type":"int","description":"Minimum number of digits","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[MinDigits(4)]\npublic int Pin { get; set; }","errorCode":"MinDigitsValidationError"},{"name":"MaxDigits","description":"Validates that an integer value has at most a specified number of digits.","supportedTypes":["int","uint","long","ulong"],"constructorParams":[{"name":"maxDigits","type":"int","description":"Maximum number of digits","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[MaxDigits(2)]\npublic int Percentage { get; set; }","errorCode":"MaxDigitsValidationError"}]},{"category":"Date","description":"Attributes for validating DateTime values including ranges, relative dates, and calendar properties.","attributes":[{"name":"PastDate","description":"Validates that a date is in the past.","supportedTypes":["DateTime","DateTime?","DateTimeOffset","DateTimeOffset?"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[PastDate]\npublic DateTime BirthDate { get; set; }","errorCode":"PastDateValidationError"},{"name":"FutureDate","description":"Validates that a date is in the future.","supportedTypes":["DateTime","DateTime?","DateTimeOffset","DateTimeOffset?"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[FutureDate]\npublic DateTime ExpiryDate { get; set; }","errorCode":"FutureDateValidationError"},{"name":"Today","description":"Validates that a date is today (ignoring time component).","supportedTypes":["DateTime","DateTime?","DateTimeOffset","DateTimeOffset?"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[Today]\npublic DateTime TransactionDate { get; set; }","errorCode":"TodayValidationError"},{"name":"NotTodayDate","description":"Validates that a date is not today.","supportedTypes":["DateTime","DateTime?","DateTimeOffset","DateTimeOffset?"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[NotTodayDate]\npublic DateTime ScheduledDate { get; set; }","errorCode":"NotTodayDateValidationError"},{"name":"NotInPast","description":"Validates that a date is today or in the future.","supportedTypes":["DateTime","DateTime?","DateTimeOffset","DateTimeOffset?"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[NotInPast]\npublic DateTime EventDate { get; set; }","errorCode":"NotInPastValidationError"},{"name":"NotInFuture","description":"Validates that a date is today or in the past.","supportedTypes":["DateTime","DateTime?","DateTimeOffset","DateTimeOffset?"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[NotInFuture]\npublic DateTime PurchaseDate { get; set; }","errorCode":"NotInFutureValidationError"},{"name":"DateRange","description":"Validates that a date falls within a specified range.","supportedTypes":["DateTime","DateTime?","DateTimeOffset","DateTimeOffset?"],"constructorParams":[{"name":"minDate","type":"string","description":"Minimum date in ISO format","required":true},{"name":"maxDate","type":"string","description":"Maximum date in ISO format","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[DateRange(\"2020-01-01\", \"2030-12-31\")]\npublic DateTime ProjectDate { get; set; }","errorCode":"DateRangeValidationError"},{"name":"TimeRange","description":"Validates that a time falls within a specified range.","supportedTypes":["DateTime","DateTime?","TimeSpan","TimeSpan?"],"constructorParams":[{"name":"startTime","type":"string","description":"Start time (e.g., '09:00')","required":true},{"name":"endTime","type":"string","description":"End time (e.g., '17:00')","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[TimeRange(\"09:00\", \"17:00\")]\npublic DateTime WorkingHours { get; set; }","errorCode":"TimeRangeValidationError"},{"name":"MinAge","description":"Validates that a date represents a minimum age.","supportedTypes":["DateTime","DateTime?"],"constructorParams":[{"name":"minimumAge","type":"int","description":"Minimum age in years","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[MinAge(18)]\npublic DateTime BirthDate { get; set; }","errorCode":"MinAgeValidationError"},{"name":"MaxAge","description":"Validates that a date represents a maximum age.","supportedTypes":["DateTime","DateTime?"],"constructorParams":[{"name":"maximumAge","type":"int","description":"Maximum age in years","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[MaxAge(65)]\npublic DateTime BirthDate { get; set; }","errorCode":"MaxAgeValidationError"},{"name":"AgeRange","description":"Validates that a date represents an age within a specified range.","supportedTypes":["DateTime","DateTime?"],"constructorParams":[{"name":"minimumAge","type":"int","description":"Minimum age in years","required":true},{"name":"maximumAge","type":"int","description":"Maximum age in years","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[AgeRange(18, 65)]\npublic DateTime BirthDate { get; set; }","errorCode":"AgeRangeValidationError"},{"name":"DayOfWeek","description":"Validates that a date falls on one of the specified days of the week.","supportedTypes":["DateTime","DateTime?","DateTimeOffset","DateTimeOffset?"],"constructorParams":[{"name":"days","type":"params DayOfWeek[]","description":"Allowed days of the week","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[DayOfWeek(DayOfWeek.Monday, DayOfWeek.Wednesday, DayOfWeek.Friday)]\npublic DateTime WorkDay { get; set; }","errorCode":"DayOfWeekValidationError"},{"name":"Day","description":"Validates that a date falls on one of the specified days of the month.","supportedTypes":["DateTime","DateTime?","DateTimeOffset","DateTimeOffset?"],"constructorParams":[{"name":"days","type":"params int[]","description":"Allowed days of the month (1-31)","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[Day(1, 15)]\npublic DateTime PaymentDate { get; set; }","errorCode":"DayValidationError"},{"name":"Month","description":"Validates that a date falls in one of the specified months.","supportedTypes":["DateTime","DateTime?","DateTimeOffset","DateTimeOffset?"],"constructorParams":[{"name":"months","type":"params int[]","description":"Allowed months (1-12)","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[Month(6, 7, 8)]\npublic DateTime SummerEvent { get; set; }","errorCode":"MonthValidationError"},{"name":"Year","description":"Validates that a date falls in one of the specified years.","supportedTypes":["DateTime","DateTime?","DateTimeOffset","DateTimeOffset?"],"constructorParams":[{"name":"years","type":"params int[]","description":"Allowed years","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[Year(2024, 2025)]\npublic DateTime EventDate { get; set; }","errorCode":"YearValidationError"},{"name":"Quarter","description":"Validates that a date falls in one of the specified quarters (Q1-Q4).","supportedTypes":["DateTime","DateTime?","DateTimeOffset","DateTimeOffset?"],"constructorParams":[{"name":"quarters","type":"params Quarter[]","description":"Allowed quarters","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[Quarter(Quarter.Q1, Quarter.Q2)]\npublic DateTime ReportDate { get; set; }","errorCode":"QuarterValidationError"},{"name":"LeapYear","description":"Validates that a date falls in a leap year.","supportedTypes":["DateTime","DateTime?","DateTimeOffset","DateTimeOffset?"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[LeapYear]\npublic DateTime SpecialDate { get; set; }","errorCode":"LeapYearValidationError"},{"name":"NotLeapYear","description":"Validates that a date does not fall in a leap year.","supportedTypes":["DateTime","DateTime?","DateTimeOffset","DateTimeOffset?"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[NotLeapYear]\npublic DateTime StandardYear { get; set; }","errorCode":"NotLeapYearValidationError"},{"name":"UTC","description":"Validates that a date is in UTC format.","supportedTypes":["DateTime","DateTime?"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[UTC]\npublic DateTime Timestamp { get; set; }","errorCode":"UTCValidationError"},{"name":"NotUTC","description":"Validates that a date is not in UTC format.","supportedTypes":["DateTime","DateTime?"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[NotUTC]\npublic DateTime LocalTime { get; set; }","errorCode":"NotUTCValidationError"}]},{"category":"Collection","description":"Attributes for validating collections including length, content, and element validation.","attributes":[{"name":"HasElements","description":"Validates that a collection has at least one element.","supportedTypes":["IEnumerable<T>","ICollection<T>","IList<T>","List<T>","T[]"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[HasElements]\npublic List<string> Tags { get; set; }","errorCode":"HasElementsValidationError"},{"name":"MinLength","description":"Validates that a collection has at least a minimum number of elements.","supportedTypes":["IEnumerable<T>","ICollection<T>","IList<T>","List<T>","T[]","string"],"constructorParams":[{"name":"minLength","type":"int","description":"Minimum number of elements","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[MinLength(2)]\npublic List<string> Options { get; set; }","errorCode":"MinLengthValidationError"},{"name":"MaxLength","description":"Validates that a collection does not exceed a maximum number of elements.","supportedTypes":["IEnumerable<T>","ICollection<T>","IList<T>","List<T>","T[]","string"],"constructorParams":[{"name":"maxLength","type":"int","description":"Maximum number of elements","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[MaxLength(10)]\npublic List<string> Categories { get; set; }","errorCode":"MaxLengthValidationError"},{"name":"Length","description":"Validates that a collection has exactly the specified number of elements.","supportedTypes":["IEnumerable<T>","ICollection<T>","IList<T>","List<T>","T[]","string"],"constructorParams":[{"name":"length","type":"int","description":"Exact number of elements required","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[Length(3)]\npublic int[] Coordinates { get; set; }","errorCode":"LengthValidationError"},{"name":"UniqueElements","description":"Validates that all elements in a collection are unique.","supportedTypes":["IEnumerable<T>","ICollection<T>","IList<T>","List<T>","T[]"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[UniqueElements]\npublic List<string> Tags { get; set; }","errorCode":"UniqueElementsValidationError"},{"name":"NoNullElements","description":"Validates that a collection does not contain any null elements.","supportedTypes":["IEnumerable<T>","ICollection<T>","IList<T>","List<T>","T[]"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[NoNullElements]\npublic List<string?> Names { get; set; }","errorCode":"NoNullElementsValidationError"},{"name":"ContainsElement","description":"Validates that a collection contains a specified element.","supportedTypes":["IEnumerable<T>","ICollection<T>","IList<T>","List<T>","T[]"],"constructorParams":[{"name":"element","type":"object","description":"The element that must be present","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[ContainsElement(42)]\npublic List<int> Numbers { get; set; }","errorCode":"ContainsElementValidationError"},{"name":"NotContainElement","description":"Validates that a collection does not contain a specified element.","supportedTypes":["IEnumerable<T>","ICollection<T>","IList<T>","List<T>","T[]"],"constructorParams":[{"name":"element","type":"object","description":"The element that must not be present","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[NotContainElement(0)]\npublic List<int> NonZeroNumbers { get; set; }","errorCode":"NotContainElementValidationError"},{"name":"Single","description":"Validates that a specified value appears exactly once in the collection.","supportedTypes":["IEnumerable<T>","ICollection<T>","IList<T>","List<T>","T[]"],"constructorParams":[{"name":"element","type":"object","description":"The element that must appear exactly once","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[Single(1)]\npublic List<int> Flags { get; set; }","errorCode":"SingleValidationError"},{"name":"SingleOrNone","description":"Validates that a specified value appears at most once (zero or one time) in the collection.","supportedTypes":["IEnumerable<T>","ICollection<T>","IList<T>","List<T>","T[]"],"constructorParams":[{"name":"element","type":"object","description":"The element that must appear at most once","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[SingleOrNone(1)]\npublic List<int> Flags { get; set; }","errorCode":"SingleOrNoneValidationError"}]},{"category":"General","description":"General-purpose validation attributes for null checks and equality comparisons.","attributes":[{"name":"NotNull","description":"Validates that a value is not null. This is typically the first attribute in a validation chain.","supportedTypes":["any nullable type"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[NotNull]\npublic string? Name { get; set; }","errorCode":"NotNullValidationError"},{"name":"Optional","description":"Marks a property as optional (null is allowed). Use this when null values are acceptable.","supportedTypes":["any nullable type"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[Optional]\n[EmailAddress]\npublic string? SecondaryEmail { get; set; }","errorCode":"OptionalValidationError"},{"name":"NotDefault","description":"Validates that a value is not set to its default value (0 for numbers, null for reference types, etc.).","supportedTypes":["any type"],"constructorParams":[],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[NotDefault]\npublic Guid Id { get; set; }","errorCode":"NotDefaultValidationError"},{"name":"EqualTo","description":"Validates that a value is equal to a specified value.","supportedTypes":["any type"],"constructorParams":[{"name":"value","type":"object","description":"The value to compare against","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[EqualTo(\"confirmed\")]\npublic string Status { get; set; }","errorCode":"EqualToValidationError"},{"name":"NotEqualTo","description":"Validates that a value is not equal to a specified value.","supportedTypes":["any type"],"constructorParams":[{"name":"value","type":"object","description":"The value to compare against","required":true}],"properties":["ErrorCode","Chain","ConditionalMethod"],"example":"[NotEqualTo(\"admin\")]\npublic string Username { get; set; }","errorCode":"NotEqualToValidationError"}]}],"analyzers":[{"id":"EASY001","title":"Attribute Must Inherit From System.Attribute","description":"Validation attribute must inherit from System.Attribute. Custom validation attributes must properly extend the attribute hierarchy.","category":"Inheritance","severity":"Error","fixAvailable":false},{"id":"EASY002","title":"Attribute Must Have Proper AttributeUsage","description":"Validation attribute must have proper AttributeUsage attribute configured for properties, fields, or parameters.","category":"Design","severity":"Error","fixAvailable":true},{"id":"EASY003","title":"Validation Attribute Must Implement IValidationAttribute<T>","description":"Validation attribute must implement IValidationAttribute<T> to be recognized by the source generator.","category":"Design","severity":"Error","fixAvailable":true},{"id":"EASY004","title":"DivisibleBy Divisor Cannot Be Zero","description":"The divisor passed to 'DivisibleByAttribute' cannot be zero as it would cause a division by zero error.","category":"Usage","severity":"Error","fixAvailable":false},{"id":"EASY005","title":"PowerOf Value Must Be Greater Than One","description":"The value passed to 'PowerOfAttribute' must be greater than 1 for meaningful power validation.","category":"Usage","severity":"Error","fixAvailable":false},{"id":"EASY006","title":"Collection Element Type Mismatch","description":"The element passed to collection attributes must match the property's element type.","category":"Type Safety","severity":"Error","fixAvailable":false},{"id":"EASY007","title":"Duplicate Chain Name","description":"Multiple validation attributes with the same chain name found on a single member. Each chain should have unique attributes.","category":"Chain Validation","severity":"Warning","fixAvailable":true},{"id":"EASY008","title":"Validation Chain Needs Reordering","description":"Validation chain attributes need reordering to ensure proper type flow between transforming validators.","category":"Chain Validation","severity":"Warning","fixAvailable":true},{"id":"EASY009","title":"Chain Needs NotNull Injection","description":"Validation chain needs NotNull attribute injection to handle nullable types properly.","category":"Chain Validation","severity":"Warning","fixAvailable":true},{"id":"EASY010","title":"Incompatible Chain Types","description":"Validation chain has incompatible types. The output type of one validator doesn't match the input type of the next.","category":"Chain Validation","severity":"Error","fixAvailable":false},{"id":"EASY011","title":"Conditional Method Is Missing","description":"The conditional method specified in ConditionalMethod property is missing from the containing class.","category":"Conditional Validation","severity":"Error","fixAvailable":true},{"id":"EASY012","title":"Conditional Method Invalid Parameter Count","description":"Conditional method must accept exactly zero or one parameter of type IChainResult.","category":"Conditional Validation","severity":"Error","fixAvailable":true},{"id":"EASY013","title":"Conditional Method Parameter Type Mismatch","description":"Conditional method's first parameter must be of type IChainResult.","category":"Conditional Validation","severity":"Error","fixAvailable":true},{"id":"EASY014","title":"Conditional Method Return Type Mismatch","description":"Conditional method must return bool or ValueTask<bool>.","category":"Conditional Validation","severity":"Error","fixAvailable":true},{"id":"EASY015","title":"Invalid Conditional Method Name","description":"Conditional method name is not a valid C# method identifier.","category":"Conditional Validation","severity":"Error","fixAvailable":true},{"id":"EASY016","title":"Missing Required Validation Type","description":"Class is missing required validation type(s) - must implement IGenerate interface.","category":"Setup","severity":"Error","fixAvailable":true},{"id":"EASY017","title":"ValidationContext Property Diagnostic","description":"Issues with ValidationContext property configuration in custom attributes.","category":"Context","severity":"Warning","fixAvailable":false},{"id":"EASY018","title":"Public Method Can Cause Confusion","description":"Public method with validation attributes can cause confusion in validation processing. Consider making it private or internal.","category":"Design","severity":"Warning","fixAvailable":true},{"id":"EASY019","title":"Conflicting Base Class Inheritance","description":"Containing class inherits another class and is required to inherit a specific base class for validation.","category":"Inheritance","severity":"Error","fixAvailable":false}],"fixers":[{"id":"FIX001","title":"Chain Reordering","description":"Automatically reorders validation attributes in a chain to ensure proper type flow. When attribute output types don't match the next attribute's input type, this fixer reorders them correctly.","fixesAnalyzers":["EASY008","EASY010"]},{"id":"FIX002","title":"Conditional Method Implementation","description":"Generates the missing conditional method when ConditionalMethod is specified but the method doesn't exist. Creates a method with proper signature.","fixesAnalyzers":["EASY011"]},{"id":"FIX003","title":"Conditional Method Name","description":"Fixes invalid conditional method names by correcting them to valid C# identifiers or using nameof() for compile-time safety.","fixesAnalyzers":["EASY015"]},{"id":"FIX004","title":"Duplicate Attribute in Chain","description":"Resolves duplicate validation attributes in the same chain by either removing duplicates or assigning them to different chains.","fixesAnalyzers":["EASY007"]},{"id":"FIX005","title":"Missing Types (IGenerate)","description":"Adds the required IGenerate interface implementation when a class has validation attributes but doesn't implement IGenerate.","fixesAnalyzers":["EASY016"]},{"id":"FIX006","title":"NotNull Injection","description":"Automatically injects NotNull attribute at the beginning of a validation chain when validating nullable types that need null checks.","fixesAnalyzers":["EASY009"]},{"id":"FIX007","title":"Public Method Visibility","description":"Changes public methods with validation attributes to internal or private to avoid confusion in validation processing.","fixesAnalyzers":["EASY018"]},{"id":"FIX008","title":"Validation Attribute Usage","description":"Fixes validation attribute implementations by adding proper AttributeUsage or ensuring correct interface implementation.","fixesAnalyzers":["EASY002","EASY003"]},{"id":"FIX009","title":"Conditional Method Parameter Fix","description":"Fixes conditional method signatures by correcting the parameter type to IChainResult or adjusting parameter count.","fixesAnalyzers":["EASY012","EASY013"]},{"id":"FIX010","title":"Conditional Method Return Type","description":"Fixes conditional method return types to bool or ValueTask<bool> as required by the validation system.","fixesAnalyzers":["EASY014"]}],"features":[{"name":"Validation Chains","description":"Group related validations using the Chain property. Attributes with the same chain name run together, and if one fails, subsequent attributes in the chain can still execute.","example":"[NotNull(Chain = \"shipping\")]\n[FutureDate(Chain = \"shipping\")]\npublic DateTime? ShippingDate { get; set; }"},{"name":"Conditional Validation","description":"Use ConditionalMethod property to specify a method that returns bool or ValueTask<bool> to conditionally run validation.","example":"[NotNull(ConditionalMethod = nameof(ShouldValidate))]\npublic string? OptionalField { get; set; }\n\nprivate bool ShouldValidate(IChainResult result) => someCondition;"},{"name":"Async Validation","description":"Create custom async validation attributes by implementing IAsyncValidationAttribute<T> for database or API calls. Use ValidateAsync() method for async validation.","example":"var result = await model.ValidateAsync(config);"},{"name":"Parameter Validation","description":"Apply validation attributes to method parameters. The source generator creates an overload that validates parameters before execution.","example":"public void Process([NotNull] string? value, [Range(1, 100)] int count) { }"},{"name":"ValidationContext","description":"Access the parent model instance in custom validation attributes using [ValidationContext] property for cross-property validation.","example":"[ValidationContext]\npublic MyModel? Context { get; init; }"},{"name":"Dependency Injection","description":"Inject services into async validation attributes via init properties. Configure via ValidationConfig.ServiceProvider.","example":"public IMyService? MyService { get; init; }\n\nvar config = new ValidationConfig { ServiceProvider = services };\nvar result = await model.ValidateAsync(config);"},{"name":"Custom Error Codes","description":"All attributes support ErrorCode property for custom error identification in your application.","example":"[NotNull(ErrorCode = \"USER_NAME_REQUIRED\")]\npublic string? Name { get; set; }"},{"name":"Source Generation","description":"EasyValidate uses C# source generators to create validation code at compile time, ensuring zero runtime reflection overhead."},{"name":"Roslyn Analyzers","description":"Built-in analyzers provide compile-time feedback for common mistakes like missing IGenerate, incompatible chain types, or invalid conditional methods."},{"name":"Code Fixers","description":"Automatic code fixes for common issues like reordering validation chains, adding missing methods, or injecting NotNull attributes."}],"bestPractices":[{"title":"Always Use Partial Classes","description":"Classes implementing IGenerate must be declared as partial for the source generator to add the Validate() method.","example":"public partial class User : IGenerate { }"},{"title":"Order Matters in Chains","description":"Put NotNull/Optional attributes first, then NotEmpty, then specific validations. The analyzer will warn if order is incorrect.","example":"[NotNull]      // First: handle null\n[NotEmpty]     // Second: handle empty\n[EmailAddress] // Third: validate format\npublic string? Email { get; set; }"},{"title":"Use Meaningful Error Codes","description":"Set ErrorCode property for better error handling and localization in your application.","example":"[NotNull(ErrorCode = \"FIELD_REQUIRED\")]\n[EmailAddress(ErrorCode = \"INVALID_EMAIL_FORMAT\")]\npublic string? Email { get; set; }"},{"title":"Use nameof() for ConditionalMethod","description":"Use nameof() operator for compile-time safety when specifying conditional methods.","example":"[NotNull(ConditionalMethod = nameof(ShouldValidate))]"},{"title":"Handle Async Attributes Properly","description":"When using IAsyncValidationAttribute, always implement both Validate() (for sync calls) and ValidateAsync() methods.","example":"public override AttributeResult Validate(...) => AttributeResult.Success();\npublic async Task<AttributeResult> ValidateAsync(...) { /* async logic */ }"}]}