### Example Output of Luthor Validation Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/comprehensive-example.mdx Illustrates the expected output when running the comprehensive Luthor example, showing both successful and failed validation scenarios, including specific error messages. ```text === Luthor Comprehensive Example === 📝 Testing valid registration... ✅ Registration successful! Name: John Doe Email: john.doe@example.com Account Type: personal City: Springfield Company: Tech Corp ================================================== ❌ Testing invalid registration... ✅ Validation failed as expected. Errors found: • First Name: firstName must be at least 2 characters long • Last Name: lastName must be at least 1 characters long • Email: email_address must be a valid email address • Password: password must be at least 8 characters long • Confirm Password: Passwords must match • Phone: Phone number is required for business accounts • Age: age must be at least 18 • City: city must be at least 1 characters long • Terms: acceptTerms is required ================================================== 🏢 Testing business account validation... ✅ Business account validation: Phone number is required for business accounts ✅ Personal account doesn't require phone number ================================================== 💼 Testing employment date validation... ✅ Employment date validation: End date must be after start date ``` -------------------------------- ### Complete Validation Example with ErrorKeys Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/result.mdx Demonstrates validating a complex object with nested structures and accessing specific validation errors using generated ErrorKeys for compile-time safety. This example shows how to handle both successful validation and various error scenarios. ```dart import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:luthor/luthor.dart'; part 'user_profile.freezed.dart'; part 'user_profile.g.dart'; @luthor @freezed abstract class UserProfile with _$UserProfile { const factory UserProfile({ required String name, required String email, required UserSettings settings, }) = _UserProfile; factory UserProfile.fromJson(Map json) => _$UserProfileFromJson(json); } @luthor @freezed abstract class UserSettings with _$UserSettings { const factory UserSettings({ required String theme, required bool notifications, }) = _UserSettings; factory UserSettings.fromJson(Map json) => _$UserSettingsFromJson(json); } void main() { final result = $UserProfileValidate({ 'name': '', // Invalid - empty string 'email': 'invalid-email', // Invalid - not an email 'settings': { 'theme': null, // Invalid - required field 'notifications': 'yes', // Invalid - should be boolean }, }); switch (result) { case SchemaValidationError(): print('Validation failed:'); // Type-safe error access with ErrorKeys final nameError = result.getError(UserProfileErrorKeys.name); final emailError = result.getError(UserProfileErrorKeys.email); final themeError = result.getError(UserProfileErrorKeys.settings.theme); final notificationsError = result.getError(UserProfileErrorKeys.settings.notifications); if (nameError != null) print('Name: $nameError'); if (emailError != null) print('Email: $emailError'); if (themeError != null) print('Theme: $themeError'); if (notificationsError != null) print('Notifications: $notificationsError'); case SchemaValidationSuccess(data: final profile): print('✅ Valid profile: ${profile.name}'); } } ``` -------------------------------- ### Install Luthor Core Package Source: https://context7.com/exaby73/luthor/llms.txt Add the core Luthor package to your Dart or Flutter project using the respective package managers. ```bash # Dart dart pub add luthor # Flutter flutter pub add luthor ``` -------------------------------- ### Example: Tree Structure with `forwardRef()` Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/schemas/defining-schemas.mdx Demonstrates defining a tree structure where nodes can have optional parent references and a list of child nodes, using `forwardRef()` for self-referencing. ```dart late Validator treeNodeSchema; treeNodeSchema = l.schema({ 'id': l.string().required(), 'value': l.string().required(), 'parent': forwardRef(() => treeNodeSchema), // Optional parent reference 'children': l.list( validators: [forwardRef(() => treeNodeSchema.required())], ), // List of child nodes }); ``` -------------------------------- ### Generated SchemaKeys Example Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/schemas/code-generation.mdx Type-safe constants generated for schema definition, mapping Dart field names to JSON field names. ```dart // Generated code - Dart field names as keys, JSON field names as values const UserSchemaKeys = ( name: "name", email: "email", age: "age", ); ``` -------------------------------- ### Complete UserProfile and UserSettings Example Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/schemas/code-generation.mdx Demonstrates the full code generation for UserProfile and UserSettings, including validation and JSON serialization. Shows how to use the generated validation function and extension methods. ```dart import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:luthor/luthor.dart'; part 'user_profile.freezed.dart'; part 'user_profile.g.dart'; @luthor @freezed abstract class UserProfile with _$UserProfile { const factory UserProfile({ required int id, required String name, @JsonKey(name: 'email_addr') required String email, required UserSettings settings, }) = _UserProfile; factory UserProfile.fromJson(Map json) => _$UserProfileFromJson(json); } @luthor @freezed abstract class UserSettings with _$UserSettings { const factory UserSettings({ required String theme, required bool notifications, }) = _UserSettings; factory UserSettings.fromJson(Map json) => _$UserSettingsFromJson(json); } void main() { // Using generated validation final result = $UserProfileValidate({ 'id': 1, 'name': 'John Doe', 'email_addr': 'john@example.com', 'settings': { 'theme': 'dark', 'notifications': true, }, }); switch (result) { case SchemaValidationSuccess(data: final profile): print('✅ Valid profile: ${profile.name}'); // Use the extension method for validation final selfValidation = profile.validateSelf(); print('Self-validation: $selfValidation'); case SchemaValidationError(errors: final errors): // Type-safe error access using ErrorKeys final nameError = result.getError(UserProfileErrorKeys.name); final emailError = result.getError(UserProfileErrorKeys.email); final themeError = result.getError(UserProfileErrorKeys.settings.theme); print('❌ Validation errors:'); if (nameError != null) print('Name: $nameError'); if (emailError != null) print('Email: $emailError'); if (themeError != null) print('Theme: $themeError'); } } ``` -------------------------------- ### Class with JsonKey Annotations Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/schemas/code-generation.mdx Example of a class using @JsonKey to map Dart fields to different JSON field names. ```dart @luthor @freezed abstract class ApiUser with _$ApiUser { const factory ApiUser({ required String name, @JsonKey(name: 'email_address') required String email, @JsonKey(name: 'user_age') required int age, }) = _ApiUser; factory ApiUser.fromJson(Map json) => _$ApiUserFromJson(json); } ``` -------------------------------- ### Usage of SchemaKeys in Schema Definition Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/schemas/code-generation.mdx Example of using generated SchemaKeys within a Luthor schema definition for type-safe field access. ```dart // Generated schema using SchemaKeys Validator $UserSchema = l.withName('User').schema({ UserSchemaKeys.name: l.string().required(), UserSchemaKeys.email: l.string().email().required(), UserSchemaKeys.age: l.int().required(), }); ``` -------------------------------- ### Add Luthor Code Generation to Flutter Project Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/installation.mdx Install Luthor and its code generation dependencies for Flutter projects using build_runner. ```bash flutter pub add dev:build_runner dev:luthor_generator ``` -------------------------------- ### Add Luthor Code Generation to Dart Project Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/installation.mdx Install Luthor and its code generation dependencies for Dart projects using build_runner. ```bash dart pub add dev:build_runner dev:luthor_generator ``` -------------------------------- ### Basic String Validation with startsWith Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/modifiers/string-modifiers/starts-with.mdx Use the `startsWith` modifier directly on a string schema to validate its prefix. This example shows a simple validation check. ```dart import 'package:luthor/luthor.dart'; void main() { final validator = l.string().startsWith('Hello'); print(validator.validateValue('Hello World!')); } ``` -------------------------------- ### Key and Value Validation Setup Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/single-values/map.mdx Configure specific validators for map keys and values using `keyValidator` and `valueValidator` parameters. This ensures all keys are strings and all values are integers. ```dart final validator = l.map( keyValidator: l.string().required(), valueValidator: l.int().required(), ); ``` -------------------------------- ### Reuse and Compose Schemas Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/schemas/defining-schemas.mdx Schemas can be reused and composed to build complex data structures. This example shows composing a `personSchema` with an `addressSchema`. ```dart final addressSchema = l.schema({ 'street': l.string().required(), 'city': l.string().required(), 'zip': l.string().required(), }); final personSchema = l.schema({ 'name': l.string().required(), 'home_address': addressSchema.required(), 'work_address': addressSchema, // Optional }); ``` -------------------------------- ### User Registration Form Validation with Luthor and Freezed Source: https://context7.com/exaby73/luthor/llms.txt This example showcases a user registration form with nested schemas, cross-field validation (passwords match, phone required for business accounts), and @JsonKey mapping for email and state/postal codes. It uses Luthor's schema validation and Freezed for data modeling. The main function demonstrates how to use the generated $RegistrationValidate function and handle validation results using Dart 3 pattern matching. ```dart import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:luthor/luthor.dart'; part 'registration.freezed.dart'; part 'registration.g.dart'; bool passwordsMatch(Object? value, Map data) => value == data['password']; bool phoneRequiredForBusiness(Object? value, Map data) { if (data['accountType'] == 'business') { return value != null && value.toString().isNotEmpty; } return true; } @luthor @freezed abstract class Address with _$Address { const factory Address({ required String street, required String city, @JsonKey(name: 'state_code') required String state, @JsonKey(name: 'postal_code') required String zip, }) = _Address; factory Address.fromJson(Map json) => _$AddressFromJson(json); } @luthor @freezed abstract class Registration with _$Registration { const factory Registration({ @HasMin(2) @HasMax(50) required String firstName, @IsEmail() @JsonKey(name: 'email_address') required String email, @HasMin(8) required String password, @WithSchemaCustomValidator(passwordsMatch, message: 'Passwords must match') required String confirmPassword, required String accountType, @WithSchemaCustomValidator(phoneRequiredForBusiness, message: 'Phone required for business accounts') String? phoneNumber, @HasMin(18) @HasMax(120) required int age, required Address address, required bool acceptTerms, }) = _Registration; factory Registration.fromJson(Map json) => _$RegistrationFromJson(json); } void main() { final result = $RegistrationValidate({ 'firstName': 'Jane', 'email_address': 'jane@acme.com', 'password': 'SecurePass1', 'confirmPassword': 'SecurePass1', 'accountType': 'personal', 'age': 28, 'address': { 'street': '1 Main St', 'city': 'Metropolis', 'state_code': 'NY', 'postal_code': '10001', }, 'acceptTerms': true, }); switch (result) { case SchemaValidationSuccess(data: final reg): print('✅ Registered: ${reg.firstName}, ${reg.email}'); print(' City: ${reg.address.city}'); case SchemaValidationError(): // Type-safe error access via generated ErrorKeys final emailErr = result.getError(RegistrationErrorKeys.email); final pwdErr = result.getError(RegistrationErrorKeys.confirmPassword); final cityErr = result.getError(RegistrationErrorKeys.address.city); if (emailErr != null) print('Email: $emailErr'); if (pwdErr != null) print('Confirm Password: $pwdErr'); if (cityErr != null) print('City: $cityErr'); } } ``` -------------------------------- ### Basic Map Validation Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/single-values/map.mdx Use `l.map()` for basic validation of map structures. This example shows validation of an empty map and a map with string keys and values. ```dart import 'package:luthor/luthor.dart'; void main() { // Basic map validation final validator = l.map(); print(validator.validateValue({'key': 'value'})); // Map with key and value validators final typedValidator = l.map( keyValidator: l.string().required(), valueValidator: l.int().required(), ); print(typedValidator.validateValue({ 'key1': 42, 'key2': 100, })); } ``` -------------------------------- ### Basic URL Validation Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/modifiers/string-modifiers/url.mdx Use the `.url()` modifier to validate if a string is a valid URL. This example shows basic validation and error handling. ```dart import 'package:luthor/luthor.dart'; void main() { final validator = l.string().url(); print(validator.validateValue('https://dart.dev')); // Success print(validator.validateValue('not a url')); // Error // With allowed schemes final httpsOnly = l.string().url(allowedSchemes: ['https']); print(httpshttpsOnly.validateValue('https://dart.dev')); // Success print(httpsOnly.validateValue('http://dart.dev')); // Error } ``` -------------------------------- ### Schema-Aware Custom Validation Example Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/modifiers/custom.mdx Demonstrates how to use `customWithSchema` for cross-field validation in Dart. This is useful for scenarios like password confirmation or comparing numeric ranges. ```dart import 'package:luthor/luthor.dart'; bool passwordsMatch(Object? value, Map data) { return value == data['password']; } bool maxAgeGreaterThanMin(Object? value, Map data) { if (value is int && data['minAge'] is int) { return value > (data['minAge'] as int); } return false; } void main() { final schema = l.schema({ 'password': l.string().min(8).required(), 'confirmPassword': l .string() .customWithSchema(passwordsMatch, message: 'Passwords must match') .required(), 'minAge': l.int().required(), 'maxAge': l .int() .customWithSchema( maxAgeGreaterThanMin, message: 'Max age must be greater than min age', ) .required(), }); final result = schema.validateSchema({ 'password': 'password123', 'confirmPassword': 'password123', 'minAge': 18, 'maxAge': 65, }); print(result); // Success } ``` -------------------------------- ### Validate String Max Length with Freezed and Annotations Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/modifiers/string-modifiers/max.mdx This example demonstrates using the `@HasMax` annotation with Freezed to define a maximum string length within a schema. It includes schema validation and error handling. ```dart import 'package:luthor/luthor.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'max.freezed.dart'; part 'max.g.dart'; @luthor @freezed abstract class MaxSchema with _$MaxSchema { const factory MaxSchema({ @HasMax(5) required String value, }) = _MaxSchema; factory MaxSchema.fromJson(Map json) => _$MaxSchemaFromJson(json); } void main() { final result = $MaxSchemaValidate({'value': 'Hello'}); switch (result) { case SchemaValidationSuccess(data: final data): print('✅ Valid: ${data.value}'); case SchemaValidationError(errors: final errors): print('❌ Errors: $errors'); } } ``` -------------------------------- ### Validate a File value directly Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/single-values/file.mdx Use `l.file()` to validate common file-like types directly. This example shows validation of a `Uint8List` and a non-file type. ```dart import "dart:typed_data"; import "package:luthor/luthor.dart"; void main() { final validator = l.file(); print(validator.validateValue(Uint8List.fromList([1, 2, 3]))); // Success print(validator.validateValue('not-a-file')); // Error } ``` -------------------------------- ### Code Generation with `required` and Freezed Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/modifiers/required.mdx This example shows how to integrate Luthor's `required` modifier with Freezed for automatic validation. The `required` keyword in the Freezed class definition ensures the field is non-nullable. ```dart import 'package:luthor/luthor.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'required_schema.freezed.dart'; part 'required_schema.g.dart'; @luthor @freezed abstract class RequiredSchema with _$RequiredSchema { const factory RequiredSchema({ // Adds the required modifier to the value required String value, }) = _RequiredSchema; factory RequiredSchema.fromJson(Map json) => _$RequiredSchemaFromJson(json); } void main() { final result = $RequiredSchemaValidate({'value': 'Hello'}); switch (result) { case SchemaValidationSuccess(data: final data): print('✅ Valid: ${data.value}'); case SchemaValidationError(errors: final errors): print('❌ Errors: $errors'); } } ``` -------------------------------- ### Map Validation with Invalid Data Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/single-values/map.mdx Example demonstrating how Luthor reports errors when map keys or values do not meet the specified validation criteria. Errors are nested under 'keys' and 'values' for clarity. ```dart final validator = l.map( keyValidator: l.int().required(), valueValidator: l.string().required(), ); final result = validator.validateSchema({ 'invalidKey': 'invalidValue', // Both key and value are invalid }); // Result contains: // { // 'keys': { // 'invalidKey': ['value must be an integer'] // }, // 'values': { // 'invalidKey': ['value must be a string'] // } // } ``` -------------------------------- ### Create Starlight Project with Ion Theme Source: https://github.com/exaby73/luthor/blob/main/docs/README.md Use this command to create a new Astro project with the Starlight Ion theme template. ```bash npm create astro@latest -- --template louisescher/starlight-ion-theme ``` -------------------------------- ### Project Commands Source: https://github.com/exaby73/luthor/blob/main/docs/README.md Common commands for managing your Astro + Starlight project. Run these from the project root. ```bash npm install ``` ```bash npm run dev ``` ```bash npm run build ``` ```bash npm run preview ``` ```bash npm run astro ... ``` ```bash npm run astro -- --help ``` -------------------------------- ### Date Range Validation Function Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/modifiers/custom.mdx Validates that an end date is after a start date, useful for date range selections. ```dart bool endDateAfterStartDate(Object? value, Map data) { if (value is DateTime && data['startDate'] is DateTime) { return value.isAfter(data['startDate'] as DateTime); } return false; } ``` -------------------------------- ### Project Structure Overview Source: https://github.com/exaby73/luthor/blob/main/docs/README.md This is a typical project structure for an Astro + Starlight project using the Ion theme. Starlight content is located in `src/content/docs/`. ```bash . ├── public/ ├── src/ │ ├── assets/ │ ├── components/ │ ├── content/ │ │ ├── docs/ │ │ └── config.ts │ ├── icons/ │ ├── schemas/ │ ├── styles/ │ ├── utils/ │ └── env.d.ts ├── astro.config.mjs ├── package.json └── tsconfig.json ``` -------------------------------- ### Run Code Generation Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/schemas/code-generation.mdx Execute the build_runner to generate code from your annotated classes. ```bash dart run build_runner build ``` -------------------------------- ### Define Signup Form with Custom Validator Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/schemas/code-generation.mdx Define a signup form with email, password, and a custom validator for password confirmation. The `passwordsMatch` function ensures the two password fields are identical. ```dart bool passwordsMatch(Object? value, Map data) { return value == data['password']; } @luthor @freezed abstract class SignupForm with _$SignupForm { const factory SignupForm({ @IsEmail() required String email, @HasMin(8) required String password, @WithSchemaCustomValidator(passwordsMatch, message: 'Passwords must match') required String confirmPassword, }) = _SignupForm; factory SignupForm.fromJson(Map json) => _$SignupFormFromJson(json); } ``` -------------------------------- ### Basic Validator Chaining with `l` Factory Source: https://context7.com/exaby73/luthor/llms.txt Demonstrates creating optional and required string validators using the global `l` factory and chaining modifiers. Shows how to validate a single value. ```dart import 'package:luthor/luthor.dart'; void main() { // Optional string validator — null passes, wrong type fails final optionalStr = l.string(); // Required string with length bounds final nameValidator = l.string().min(2).max(50).required(); // Validate a single value final result = nameValidator.validateValue('Alice'); print(result.isValid); // true final bad = nameValidator.validateValue('A'); print(bad.isValid); // false } ``` -------------------------------- ### Basic String Contains Validation Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/modifiers/string-modifiers/contains.mdx Use the `contains()` modifier to check if a string includes a substring. This example demonstrates direct validation of a string value. ```dart import 'package:luthor/luthor.dart'; void main() { final validator = l.string().contains('World'); print(validator.validateValue('Hello World!')); } ``` -------------------------------- ### Using ErrorKeys with getError() Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/schemas/code-generation.mdx Demonstrates the type-safe usage of ErrorKeys with the getError() method, contrasting with error-prone string literals. ```dart // ❌ Error-prone string literals final emailError = result.getError('user.email'); final themeError = result.getError('settings.theme'); // ✅ Type-safe with autocomplete final emailError = result.getError(ProfileErrorKeys.user.email); final themeError = result.getError(ProfileErrorKeys.settings.theme); ``` -------------------------------- ### Basic String Validation with endsWith Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/modifiers/string-modifiers/ends-with.mdx Use the `endsWith` modifier to create a validator that checks if a string ends with 'World!'. This example demonstrates direct value validation. ```dart import 'package:luthor/luthor.dart'; void main() { final validator = l.string().endsWith('World!'); print(validator.validateValue('Hello World!')); } ``` -------------------------------- ### Validate String Max Length Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/modifiers/string-modifiers/max.mdx Use the `max` modifier to set a maximum character limit for a string. This example shows direct validation of a string value. ```dart import 'package:luthor/luthor.dart'; void main() { final validator = l.string().max(5); print(validator.validateValue('Hello World!')); } ``` -------------------------------- ### Map Validation with Code Generation Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/schemas/code-generation.mdx Illustrates using `@luthor` and `@freezed` to define classes with maps, showing how Luthor generates validators for keys and values, including forward references for complex types. ```dart @luthor @freezed abstract class GameScore with _$GameScore { const factory GameScore({ required Map scores, // Generates keyValidator: l.string(), valueValidator: l.int() Map? mentions, // Generates validators with forwardRef for Comment values }) = _GameScore; factory GameScore.fromJson(Map json) => _$GameScoreFromJson(json); } @luthor @freezed abstract class Comment with _$Comment { const factory Comment({ required String id, required String text, Map? mentions, // Self-reference: auto-detected }) = _Comment; factory Comment.fromJson(Map json) => _$CommentFromJson(json); } ``` -------------------------------- ### Generated Schema for Forward References Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/schemas/code-generation.mdx Demonstrates generated schemas for User and Comment, showcasing how Luthor handles forward references for self-referential and cross-referential types. ```dart // Generated schema for User Validator $UserSchema = l.withName('User').schema({ UserSchemaKeys.id: l.string().required(), UserSchemaKeys.username: l.string().required(), UserSchemaKeys.comments: l.list(validators: [$CommentSchema.required()]), }); // Generated schema for Comment Validator $CommentSchema = l.withName('Comment').schema({ CommentSchemaKeys.id: l.string().required(), CommentSchemaKeys.text: l.string().required(), CommentSchemaKeys.replies: l.list( validators: [forwardRef(() => $CommentSchema.required())], // Auto-detected ), CommentSchemaKeys.parent: forwardRef(() => $CommentSchema), // Auto-detected CommentSchemaKeys.mentions: l.map( keyValidator: l.string().required(), valueValidator: forwardRef(() => $CommentSchema.required()), // Auto-detected ), CommentSchemaKeys.user: forwardRef(() => $UserSchema), // Explicit annotation }); ``` -------------------------------- ### Add Luthor to Dart Project Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/installation.mdx Use this command to add Luthor as a dependency in a standard Dart project. ```bash dart pub add luthor ``` -------------------------------- ### Auto-Generate Schema for External Classes Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/schemas/code-generation.mdx Demonstrates how Luthor can auto-generate schemas for classes without the `@luthor` annotation, provided they meet compatibility requirements like having named parameters and a `fromJson` factory. ```dart // External class without @luthor but compatible for auto-generation @freezed abstract class ExternalUser with _$ExternalUser { const factory ExternalUser({ required String name, required String email, int? age, }) = _ExternalUser; factory ExternalUser.fromJson(Map json) => _$ExternalUserFromJson(json); } // Class with @luthor that references ExternalUser @luthor @freezed abstract class UserProfile with _$UserProfile { const factory UserProfile({ required int id, required ExternalUser user, // Auto-generated schema ExternalUser? user2, // Auto-generated schema List? friends, // Auto-generated schema }) = _UserProfile; factory UserProfile.fromJson(Map json) => _$UserProfileFromJson(json); } ``` -------------------------------- ### Generated List Schema Validation Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/single-values/list.mdx When using the Luthor code generator, list validators are automatically created for schema properties. This example shows validation of a list of integers and a list of optional nullable strings. ```dart import 'package:luthor/luthor.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'list_schema.freezed.dart'; part 'list_schema.g.dart'; @luthor @freezed abstract class ListSchema with _$ListSchema { const factory ListSchema({ required List numbers, List? optionalNullableStrings, }) = _ListSchema; factory ListSchema.fromJson(Map json) => _$ListSchemaFromJson(json); } void main() { // Using generated validation function final result = $ListSchemaValidate({ 'numbers': [1, 2, 3], 'optionalNullableStrings': ['hello', null, 'world'], }); switch (result) { case SchemaValidationSuccess(data: final data): print('✅ Valid: ${data.numbers}'); case SchemaValidationError(errors: final errors): print('❌ Errors: $errors'); } } ``` -------------------------------- ### Usage of Generated Self-Validation Extension Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/schemas/code-generation.mdx Demonstrates how to use the generated `validateSelf()` extension method to validate a `User` instance. It shows how to handle both successful validation and validation errors. ```dart final user = User(name: 'John', email: 'john@example.com', age: 30); // Validate the instance against its own schema final result = user.validateSelf(); switch (result) { case SchemaValidationSuccess(data: final validatedUser): print('Valid: $validatedUser'); case SchemaValidationError(errors: final errors): print('Errors: $errors'); } ``` -------------------------------- ### Add Luthor to Flutter Project Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/installation.mdx Use this command to add Luthor as a dependency in a Flutter project. ```bash flutter pub add luthor ``` -------------------------------- ### Validate String Length with `length()` Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/modifiers/string-modifiers/length.mdx Use the `length()` modifier to create a validator that checks if a string's length is exactly the specified number. This example validates a string to be exactly 5 characters long. ```dart import 'package:luthor/luthor.dart'; void main() { final validator = l.string().length(5); print(validator.validateValue('Hello')); } ``` -------------------------------- ### Validate a File field with code generation Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/single-values/file.mdx Apply the `@IsFile()` annotation to a field in a Freezed class to enable file validation when using luthor's code generation. This example demonstrates validating a `profileImage` field. ```dart import "dart:typed_data"; import "package:freezed_annotation/freezed_annotation.dart"; import "package:luthor/luthor.dart"; part 'file_schema.freezed.dart'; part 'file_schema.g.dart'; @luthor @freezed abstract class FileSchema with _$FileSchema { const factory FileSchema({ @isFile /* OR @IsFile() */ required Object profileImage, String? description, }) = _FileSchema; factory FileSchema.fromJson(Map json) => _$FileSchemaFromJson(json); } void main() { final result = $FileSchemaValidate({ 'profileImage': Uint8List.fromList([1, 2, 3]), 'description': 'Avatar upload', }); switch (result) { case SchemaValidationSuccess(data: final data): print('✅ Valid: ${data.description}'); case SchemaValidationError(errors: final errors): print('❌ Errors: $errors'); } } ``` -------------------------------- ### String Validation with Length and Required Constraints Source: https://context7.com/exaby73/luthor/llms.txt Creates a required string validator with minimum and maximum length constraints. Shows how to handle validation results using a switch statement. ```dart import 'package:luthor/luthor.dart'; void main() { final v = l.string().min(3).max(20).required(); final ok = v.validateValue('Hello'); switch (ok) { case SingleValidationSuccess(data: final s): print(s); // Hello case SingleValidationError(errors: final e): print(e); } final fail = v.validateValue('Hi'); print(fail.isValid); // false — too short } ``` -------------------------------- ### Test Employment Data Validation Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/comprehensive-example.mdx Tests the validation of employment details within a user registration. This specific test case includes an employment record where the end date is before the start date, expecting a validation error. ```dart void testEmploymentValidation() { final employmentData = { 'firstName': 'Bob', 'lastName': 'Johnson', 'email_address': 'bob@example.com', 'password': 'SecurePass123', 'confirmPassword': 'SecurePass123', 'accountType': 'personal', 'age': 30, 'address': { 'street': '789 Work Street', 'city': 'Job City', 'state_code': 'TX', 'postal_code': '75001', 'country': 'USA', }, 'employment': { 'company_name': 'Previous Corp', 'position': 'Manager', 'start_date': '2020-01-01', 'end_date': '2019-01-01', // End date before start date! 'salary': 80000.0, }, 'acceptTerms': true, }; } ``` -------------------------------- ### Generated Map Validation with Freezed Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/single-values/map.mdx Demonstrates using Luthor with Freezed to generate validation code for a map schema. This approach is useful for complex data structures. ```dart import 'package:luthor/luthor.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'map_schema.freezed.dart'; part 'map_schema.g.dart'; @luthor @freezed abstract class MapSchema with _$MapSchema { const factory MapSchema({ required Map scores, }) = _MapSchema; factory MapSchema.fromJson(Map json) => _$MapSchemaFromJson(json); } void main() { // Using generated validation function final result = $MapSchemaValidate({ 'scores': { 'player1': 100, 'player2': 200, } }); switch (result) { case SchemaValidationSuccess(data: final data): print('✅ Valid: ${data.scores}'); case SchemaValidationError(errors: final errors): print('❌ Errors: $errors'); } } ``` -------------------------------- ### Get specific error from SchemaValidationError Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/result.mdx Use the `getError()` method on a `SchemaValidationError` to retrieve the first error message for a specific key or nested key using a dot-separated path. Returns `null` if no error exists for the given key. ```dart print(errorResult.getError('address.city')); // value is required ``` -------------------------------- ### Integer Validation with Min/Max Bounds Source: https://context7.com/exaby73/luthor/llms.txt Creates a required integer validator with minimum and maximum value constraints. Demonstrates validating integer values against these bounds. ```dart import 'package:luthor/luthor.dart'; void main() { final ageValidator = l.int().min(0).max(130).required(); print(ageValidator.validateValue(25).isValid); // true print(ageValidator.validateValue(-1).isValid); // false print(ageValidator.validateValue(200).isValid); // false } ``` -------------------------------- ### File-like Value Validation Source: https://context7.com/exaby73/luthor/llms.txt Creates a required validator that accepts various file-like types including `File`, `MultipartFile`, `XFile`, `Uint8List`, and `ByteData`. Demonstrates validating a `Uint8List`. ```dart import 'dart:typed_data'; import 'package:luthor/luthor.dart'; void main() { final v = l.file().required(); final bytes = Uint8List.fromList([0x89, 0x50, 0x4E, 0x47]); // PNG header print(v.validateValue(bytes).isValid); // true print(v.validateValue('not-a-file').isValid); // false } ``` -------------------------------- ### Define a Simple Manual Schema Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/schemas/defining-schemas.mdx Define a schema for a person object with required name and age fields. Use this for basic data validation when code generation is not preferred. ```dart import 'package:luthor/luthor.dart'; void main() { final person = l.schema({ 'name': l.string().min(1).required(), 'age': l.int().required(), }); person.validateSchema({ 'name': 'John Doe', 'age': 30, }); } ``` -------------------------------- ### Generated Keys with JsonKey Mapping Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/schemas/code-generation.mdx Shows how SchemaKeys and ErrorKeys are generated to reflect @JsonKey mappings, using Dart field names as keys and JSON field names as values. ```dart // SchemaKeys - Dart field names as keys, JSON field names as values const ApiUserSchemaKeys = ( name: "name", email: "email_address", // Record key: email (Dart) -> Value: email_address (JSON) age: "user_age", // Record key: age (Dart) -> Value: user_age (JSON) ); // ErrorKeys - Same structure const ApiUserErrorKeys = ( name: "name", email: "email_address", // Record key: email (Dart) -> Value: email_address (JSON) age: "user_age", // Record key: age (Dart) -> Value: user_age (JSON) ); ``` -------------------------------- ### Schema-based Validation with @StartsWith Annotation Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/modifiers/string-modifiers/starts-with.mdx Utilize the `@StartsWith` annotation within a Freezed schema for declarative validation. This approach integrates validation directly into your data models, simplifying the validation process for complex applications. ```dart import 'package:luthor/luthor.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'starts_with.freezed.dart'; part 'starts_with.g.dart'; @luthor @freezed abstract class StartsWithSchema with _$StartsWithSchema { const factory StartsWithSchema({ @StartsWith('Hello') required String value, }) = _StartsWithSchema; factory StartsWithSchema.fromJson(Map json) => _$StartsWithSchemaFromJson(json); } void main() { final result = $StartsWithSchemaValidate({'value': 'Hello World!'}); switch (result) { case SchemaValidationSuccess(data: final data): print('✅ Valid: ${data.value}'); case SchemaValidationError(errors: final errors): print('❌ Errors: $errors'); } } ``` -------------------------------- ### Generate Nested ErrorKeys with Dot Notation Source: https://context7.com/exaby73/luthor/llms.txt Demonstrates how Luthor generates nested ErrorKeys for nested classes using dot notation, simplifying error retrieval for deeply structured data. ```dart // Given Profile -> UserSettings nesting, generated ErrorKeys: const ProfileErrorKeys = ( id: "id", settings: ( theme: "settings.theme", notifications: "settings.notifications", ), ); // Usage: final themeError = result.getError(ProfileErrorKeys.settings.theme); ``` -------------------------------- ### Basic Schema with Code Generation Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/schemas/defining-schemas.mdx Define a person schema using Freezed and Luthor annotations for automatic code generation. This provides compile-time safety and IDE support. ```dart import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:luthor/luthor.dart'; part 'person.freezed.dart'; part 'person.g.dart'; @luthor @freezed abstract class Person with _$Person { const factory Person({ @HasMin(1) required String name, required int age, }) = _Person; factory Person.fromJson(Map json) => _$PersonFromJson(json); } void main() { final result = $PersonValidate({ 'name': 'John Doe', 'age': 30, }); print(result); } ``` -------------------------------- ### List Validation with Code Generation Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/schemas/code-generation.mdx Demonstrates how Luthor generates validators for lists, handling both non-nullable and nullable elements, as well as optional lists with nullable elements. ```dart @luthor @freezed abstract class ListExample with _$ListExample { const factory ListExample({ // Non-nullable elements - inner validator gets .required() required List tags, required List users, // Nullable elements - inner validator omits .required() required List nullableTags, required List nullableUsers, // Optional list with nullable elements List? optionalNullableTags, }) = _ListExample; factory ListExample.fromJson(Map json) => _$ListExampleFromJson(json); } ``` -------------------------------- ### Generated Schema for Compatible External Class Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/schemas/code-generation.mdx Shows the auto-generated schema for an external class (`ExternalUser`) that meets compatibility requirements. It includes the schema definition, a validation function, and an extension method for self-validation. ```dart // Auto-generated schema for ExternalUser const ExternalUserSchemaKeys = (name: "name", email: "email", age: "age"); Validator $ExternalUserSchema = l.withName('ExternalUser').schema({ ExternalUserSchemaKeys.name: l.string().required(), ExternalUserSchemaKeys.email: l.string().required(), ExternalUserSchemaKeys.age: l.int(), }); SchemaValidationResult $ExternalUserValidate( Map json, ) => $ExternalUserSchema.validateSchema(json, fromJson: ExternalUser.fromJson); extension ExternalUserValidationExtension on ExternalUser { SchemaValidationResult validateSelf() => $ExternalUserValidate(toJson()); } ``` -------------------------------- ### JsonKey Integration with SchemaKeys Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/schemas/defining-schemas.mdx Demonstrates how Luthor's generated SchemaKeys respect @JsonKey annotations for mapping JSON keys to Dart properties. This is crucial for API integrations. ```dart @luthor @freezed abstract class ApiPerson with _$ApiPerson { const factory ApiPerson({ @JsonKey(name: 'full_name') @HasMin(1) required String name, @JsonKey(name: 'user_age') required int age, }) = _ApiPerson; factory ApiPerson.fromJson(Map json) => _$ApiPersonFromJson(json); } // Generated SchemaKeys use JsonKey names const ApiPersonSchemaKeys = ( name: "full_name", // Uses JsonKey name age: "user_age", // Uses JsonKey name ); // Schema validation uses JSON field names final result = $ApiPersonValidate({ 'full_name': 'John Doe', 'user_age': 30, }); ``` -------------------------------- ### Define Main User Registration Schema Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/comprehensive-example.mdx Define the primary schema for user registration, incorporating basic fields, password validation, conditional fields, nested schemas, and acceptance of terms. Utilize various Luthor validators like `@IsEmail`, `@HasMin`, `@HasMax`, `@RegExp`, and custom validators. ```dart // Main user registration schema @luthor @freezed abstract class UserRegistration with _$UserRegistration { const factory UserRegistration({ // Basic information @HasMin(2) @HasMax(50) required String firstName, @HasMin(2) @HasMax(50) required String lastName, @IsEmail() @JsonKey(name: 'email_address') required String email, // Password fields with confirmation @HasMin(8) @RegExp(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)') required String password, @WithSchemaCustomValidator(passwordsMatch, message: 'Passwords must match') required String confirmPassword, // Account type and conditional phone required String accountType, // 'personal' or 'business' @WithSchemaCustomValidator(phoneRequiredForBusiness, message: 'Phone number is required for business accounts') String? phoneNumber, // Age validation @HasMin(18) @HasMax(100) required int age, // Address (nested schema) required Address address, // Employment (optional nested schema) Employment? employment, // Terms acceptance required bool acceptTerms, // Marketing preferences @JsonKey(name: 'newsletter_opt_in') bool? newsletterOptIn, }) = _UserRegistration; factory UserRegistration.fromJson(Map json) => _$UserRegistrationFromJson(json); } ``` -------------------------------- ### Schema Validation with Regex Annotation Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/modifiers/string-modifiers/regex.mdx Define a schema with a `@MatchRegex` annotation to automatically apply regex validation. This approach integrates seamlessly with Freezed and code generation for robust data validation. ```dart import 'package:luthor/luthor.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'regex.freezed.dart'; part 'regex.g.dart'; @luthor @freezed abstract class RegexSchema with _$RegexSchema { const factory RegexSchema({ @MatchRegex(r'^[a-zA-Z0-9]+$') required String value, }) = _RegexSchema; factory RegexSchema.fromJson(Map json) = _$RegexSchemaFromJson(json); } void main() { final result = $RegexSchemaValidate({'value': 'Hello123'}); switch (result) { case SchemaValidationSuccess(data: final data): print('✅ Valid: ${data.value}'); case SchemaValidationError(errors: final errors): print('❌ Errors: $errors'); } } ``` -------------------------------- ### Basic List Validation Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/single-values/list.mdx Use `l.list()` to create a validator for a list of items. Specify the expected type of items using `validators`. ```dart import 'package:luthor/luthor.dart'; void main() { final validator = l.list(validators: [l.int()]); print(validator.validateValue([42])); } ``` -------------------------------- ### l.withName() - Named Schemas Source: https://context7.com/exaby73/luthor/llms.txt Assigns a name to a schema, which can improve error messages by providing context. ```APIDOC ## l.withName() ### Description Assigns a name to a schema, which can improve error messages by providing context. ### Method `l.withName(String name).schema(Map schemaDefinition)` ### Parameters #### `name` (String) - Required The name to assign to the schema. #### `schemaDefinition` (Map) - Required A map defining the schema structure. ### Example ```dart import 'package:luthor/luthor.dart'; final loginSchema = l.withName('Login').schema({ 'email': l.string().email().required(), 'password': l.string().min(8).required(), }); ``` ``` -------------------------------- ### Generated ErrorKeys for Simple Classes Source: https://github.com/exaby73/luthor/blob/main/docs/src/content/docs/schemas/code-generation.mdx Type-safe constants for accessing validation errors in simple classes. ```dart // For a simple class - same structure as SchemaKeys const UserErrorKeys = ( name: "name", email: "email", age: "age", ); ```