Compare commits

..

3 commits

Author SHA1 Message Date
Patrick Stewart
b5a0c61dd3 update: update pubspec.yaml 2024-11-28 16:14:01 -07:00
Patrick Stewart
626c550e27 add: adding reflection package 2024-11-28 16:13:19 -07:00
Patrick Stewart
1373460cac add: adding in some contracts 2024-11-28 16:12:39 -07:00
42 changed files with 4979 additions and 5 deletions

View file

@ -0,0 +1,71 @@
/// Platform Contracts Library
///
/// This library provides the core contracts (interfaces) that define
/// the Platform framework's API. These contracts ensure consistency
/// and interoperability between components while enabling loose coupling
/// and dependency injection.
// Level 0: Core Foundation Contracts
// Container contracts (from packages/container)
export 'src/container/container.dart';
// Reflection contracts (from packages/container)
export 'src/reflection/reflection.dart';
// Pipeline contracts (from packages/pipeline)
export 'src/pipeline/pipeline.dart';
// Level 1: Infrastructure Contracts
// Events contracts (from packages/events)
export 'src/events/events.dart';
// Bus contracts (from packages/bus)
export 'src/bus/bus.dart';
// Model contracts (from packages/model)
export 'src/model/model.dart';
// Process contracts (from packages/process)
export 'src/process/process.dart';
// Support contracts (from packages/support)
export 'src/support/support.dart';
// Level 2: Core Services Contracts
// Queue contracts (from packages/queue)
export 'src/queue/queue.dart';
// Level 3: HTTP Layer Contracts
// Routing contracts (from packages/route)
export 'src/routing/routing.dart';
// HTTP contracts (from packages/core)
export 'src/http/http.dart';
// Testing Contracts
// Testing contracts (from packages/testing)
export 'src/testing/testing.dart';
// All contracts have been extracted from implemented packages:
// - Container & Reflection (Level 0)
// - Pipeline (Level 0)
// - Events (Level 1)
// - Bus (Level 1)
// - Model (Level 1)
// - Process (Level 1)
// - Support (Level 1)
// - Queue (Level 2)
// - Route (Level 3)
// - HTTP (Level 3)
// - Testing
// Next steps:
// 1. Update package dependencies to use these contracts
// 2. Implement contracts in each package
// 3. Add contract compliance tests
// 4. Document contract usage and patterns

View file

@ -0,0 +1,2 @@
/// Bus package contracts
export 'bus_contract.dart';

View file

@ -0,0 +1,196 @@
import 'package:meta/meta.dart';
/// Contract for commands.
///
/// Laravel-compatible: Base interface for command objects that can be
/// dispatched through the command bus.
@sealed
abstract class CommandContract {}
/// Contract for queueable commands.
///
/// Laravel-compatible: Marks commands that should be processed
/// through the queue system.
@sealed
abstract class ShouldQueueCommand implements CommandContract {}
/// Contract for command handlers.
///
/// Laravel-compatible: Defines how command handlers should process
/// their associated commands, with platform-specific typing.
@sealed
abstract class HandlerContract {
/// Handles a command.
///
/// Laravel-compatible: Core handler method with platform-specific
/// return type for more flexibility.
///
/// Parameters:
/// - [command]: The command to handle.
Future<dynamic> handle(CommandContract command);
}
/// Type definition for command pipe functions.
///
/// Platform-specific: Defines transformation functions that can modify
/// commands as they flow through the pipeline.
typedef CommandPipe = CommandContract Function(CommandContract);
/// Contract for command dispatching.
///
/// This contract defines the core interface for dispatching
/// and processing commands through the command bus.
@sealed
abstract class CommandDispatcherContract {
/// Dispatches a command.
///
/// Laravel-compatible: Core dispatch method.
///
/// Parameters:
/// - [command]: The command to dispatch.
Future<dynamic> dispatch(CommandContract command);
/// Dispatches a command synchronously.
///
/// Platform-specific: Provides explicit sync dispatch with optional handler.
///
/// Parameters:
/// - [command]: The command to dispatch.
/// - [handler]: Optional specific handler.
Future<dynamic> dispatchSync(CommandContract command,
[HandlerContract? handler]);
/// Dispatches a command immediately.
///
/// Laravel-compatible: Immediate dispatch without queueing.
/// Extended with optional handler parameter.
///
/// Parameters:
/// - [command]: The command to dispatch.
/// - [handler]: Optional specific handler.
Future<dynamic> dispatchNow(CommandContract command,
[HandlerContract? handler]);
/// Dispatches a command to queue.
///
/// Laravel-compatible: Queue-based dispatch.
///
/// Parameters:
/// - [command]: The command to queue.
Future<dynamic> dispatchToQueue(CommandContract command);
/// Finds a command batch.
///
/// Platform-specific: Provides batch lookup functionality.
///
/// Parameters:
/// - [batchId]: The batch ID to find.
Future<CommandBatchContract?> findBatch(String batchId);
/// Creates a command batch.
///
/// Laravel-compatible: Creates command batches.
/// Extended with platform-specific batch contract.
///
/// Parameters:
/// - [commands]: Commands to include in batch.
PendingCommandBatchContract batch(List<CommandContract> commands);
/// Creates a command chain.
///
/// Laravel-compatible: Creates command chains.
/// Extended with platform-specific chain contract.
///
/// Parameters:
/// - [commands]: Commands to chain.
CommandChainContract chain(List<CommandContract> commands);
/// Maps command types to handlers.
///
/// Platform-specific: Provides explicit handler mapping.
///
/// Parameters:
/// - [handlers]: Map of command types to handler types.
CommandDispatcherContract map(Map<Type, Type> handlers);
/// Applies transformation pipes to commands.
///
/// Platform-specific: Adds pipeline transformation support.
///
/// Parameters:
/// - [pipes]: List of command transformation functions.
CommandDispatcherContract pipeThrough(List<CommandPipe> pipes);
/// Dispatches after current response.
///
/// Laravel-compatible: Delayed dispatch after response.
///
/// Parameters:
/// - [command]: Command to dispatch later.
void dispatchAfterResponse(CommandContract command);
}
/// Contract for command batches.
///
/// Laravel-compatible: Defines batch structure and operations.
/// Extended with additional status tracking.
@sealed
abstract class CommandBatchContract {
/// Gets the batch ID.
String get id;
/// Gets commands in the batch.
List<CommandContract> get commands;
/// Gets batch status.
///
/// Platform-specific: Provides detailed status tracking.
String get status;
/// Whether batch allows failures.
///
/// Laravel-compatible: Controls batch failure handling.
bool get allowsFailures;
/// Gets finished command count.
///
/// Platform-specific: Tracks completion progress.
int get finished;
/// Gets failed command count.
///
/// Platform-specific: Tracks failure count.
int get failed;
/// Gets pending command count.
///
/// Platform-specific: Tracks remaining commands.
int get pending;
}
/// Contract for pending command batches.
///
/// Laravel-compatible: Defines batch configuration and dispatch.
@sealed
abstract class PendingCommandBatchContract {
/// Allows failures in batch.
///
/// Laravel-compatible: Configures failure handling.
PendingCommandBatchContract allowFailures();
/// Dispatches the batch.
///
/// Laravel-compatible: Executes the batch.
Future<void> dispatch();
}
/// Contract for command chains.
///
/// Laravel-compatible: Defines sequential command execution.
@sealed
abstract class CommandChainContract {
/// Dispatches the chain.
///
/// Laravel-compatible: Executes commands in sequence.
Future<void> dispatch();
}

View file

@ -0,0 +1,3 @@
/// Container package contracts
export 'container_contract.dart';
export 'contextual_binding_contract.dart';

View file

@ -0,0 +1,154 @@
/*
* This file is part of the Protevus Platform.
*
* (C) Protevus <developers@protevus.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
import '../reflection/reflector_contract.dart';
/// Core container contract defining dependency injection functionality.
abstract class ContainerContract {
/// Gets the reflector instance used by this container.
ReflectorContract get reflector;
/// Whether this is a root container (has no parent).
bool get isRoot;
/// Creates a child container that inherits from this container.
ContainerContract createChild();
/// Determine if the given abstract type has been bound.
bool bound(String abstract);
/// Register a binding with the container.
void bind<T>(T Function(ContainerContract) concrete, {bool shared = false});
/// Register a binding if it hasn't already been registered.
void bindIf<T>(T Function(ContainerContract) concrete, {bool shared = false});
/// Register a shared binding in the container.
void singleton<T>(T Function(ContainerContract) concrete);
/// Register a shared binding if it hasn't already been registered.
void singletonIf<T>(T Function(ContainerContract) concrete);
/// Register a scoped binding in the container.
void scoped<T>(T Function(ContainerContract) concrete);
/// Register a scoped binding if it hasn't already been registered.
void scopedIf<T>(T Function(ContainerContract) concrete);
/// Register an existing instance as shared in the container.
T instance<T>(T instance);
/// Bind a callback to resolve with Container::call.
void bindMethod(String method, Function callback);
/// Call the given Closure / class@method and inject its dependencies.
dynamic call(Function callback, [List<dynamic> parameters = const []]);
/// Wrap the given closure such that its dependencies will be injected when executed.
Function wrap(Function callback, [List<dynamic> parameters = const []]);
/// Define a contextual binding.
ContextualBindingBuilder when(Type concrete);
/// Add a contextual binding to the container.
void addContextualBinding(
Type concrete, Type abstract, dynamic implementation);
/// Register a new before resolving callback.
void beforeResolving<T>(
void Function(ContainerContract, T instance) callback);
/// Register a new resolving callback.
void resolving<T>(void Function(ContainerContract, T instance) callback);
/// Register a new after resolving callback.
void afterResolving<T>(void Function(ContainerContract, T instance) callback);
/// Checks if a type is registered in this container or its parents.
bool has<T>([Type? t]);
/// Checks if a named instance exists in this container or its parents.
bool hasNamed(String name);
/// Makes an instance of type [T].
T make<T>([Type? type]);
/// Makes an instance of type [T] asynchronously.
Future<T> makeAsync<T>([Type? type]);
/// Registers a singleton instance.
T registerSingleton<T>(T object, {Type? as});
/// Registers a factory function.
T Function(ContainerContract) registerFactory<T>(
T Function(ContainerContract) factory,
{Type? as});
/// Registers a lazy singleton.
T Function(ContainerContract) registerLazySingleton<T>(
T Function(ContainerContract) factory,
{Type? as});
/// Gets a named singleton.
T findByName<T>(String name);
/// Registers a named singleton.
T registerNamedSingleton<T>(String name, T object);
/// Tag a set of dependencies.
void tag(List<Type> abstracts, String tag);
/// Resolve all tagged dependencies.
List<T> tagged<T>(String tag);
/// Alias a type to a different name.
void alias(Type abstract, Type alias);
/// Check if a name is an alias.
bool isAlias(String name);
/// Get the alias for an abstract if available.
Type getAlias(Type abstract);
/// Extend an abstract type in the container.
void extend(Type abstract, Function(dynamic instance) extension);
/// Get the extender callbacks for a given type.
List<Function> getExtenders(Type abstract);
/// Remove all extender callbacks for a given type.
void forgetExtenders(Type abstract);
/// Remove a resolved instance from the instance cache.
void forgetInstance(Type abstract);
/// Clear all instances from the container.
void forgetInstances();
/// Clear all scoped instances from the container.
void forgetScopedInstances();
/// Flush the container of all bindings and resolved instances.
void flush();
/// Bind a new callback to an abstract's rebind event.
void rebinding(Type abstract, Function(ContainerContract, dynamic) callback);
/// Refresh an instance on the given target and method.
void refresh(Type abstract, dynamic target, String method);
}
/// Builder for contextual bindings.
abstract class ContextualBindingBuilder {
/// Specify what type needs the contextual binding.
ContextualBindingBuilder needs<T>();
/// Specify what to give for this contextual binding.
void give(dynamic implementation);
}

View file

@ -0,0 +1,42 @@
import 'package:meta/meta.dart';
/// Contract for contextual binding in dependency injection.
///
/// This contract defines the interface for creating contextual bindings,
/// allowing dependencies to be resolved differently based on context.
@sealed
abstract class ContextualBindingContract {
/// Specifies the concrete type that triggers this contextual binding.
///
/// Parameters:
/// - [concrete]: The concrete type that needs dependencies.
///
/// Returns a builder for specifying what type is needed.
ContextualNeedsContract when(Type concrete);
}
/// Contract for specifying contextual needs.
///
/// This contract defines the interface for specifying what type
/// is needed in a particular context.
@sealed
abstract class ContextualNeedsContract {
/// Specifies the type needed in this context.
///
/// Returns a builder for specifying what to give.
ContextualGiveContract needs<T>();
}
/// Contract for specifying contextual implementations.
///
/// This contract defines the interface for specifying what
/// implementation to provide in a particular context.
@sealed
abstract class ContextualGiveContract {
/// Specifies what to give for this contextual binding.
///
/// Parameters:
/// - [implementation]: The implementation to provide.
/// This can be an instance, a factory function, or a type.
void give(dynamic implementation);
}

View file

@ -0,0 +1,193 @@
import 'package:meta/meta.dart';
/// Contract for event dispatching functionality.
///
/// This contract defines the interface for dispatching events,
/// managing listeners, and handling event broadcasting.
///
/// The contract includes both Laravel-compatible methods and platform-specific
/// extensions for enhanced functionality.
abstract class EventDispatcherContract {
/// Registers an event listener.
///
/// Laravel-compatible: Registers event listeners, but with platform-specific
/// dynamic typing for more flexible event handling.
///
/// Parameters:
/// - [events]: Event type or list of event types to listen for.
/// - [listener]: Function to handle the event.
void listen(dynamic events, dynamic listener);
/// Checks if event has listeners.
///
/// Platform-specific: Provides listener existence checking.
///
/// Parameters:
/// - [eventName]: Name of the event to check.
bool hasListeners(String eventName);
/// Pushes an event for delayed processing.
///
/// Platform-specific: Supports delayed event processing.
///
/// Parameters:
/// - [event]: Name of the event.
/// - [payload]: Optional event payload.
void push(String event, [dynamic payload]);
/// Flushes delayed events.
///
/// Platform-specific: Processes delayed events immediately.
///
/// Parameters:
/// - [event]: Name of the event to flush.
Future<void> flush(String event);
/// Subscribes an event subscriber.
///
/// Laravel-compatible: Registers event subscribers, but with platform-specific
/// dynamic typing for more flexible subscription handling.
///
/// Parameters:
/// - [subscriber]: The subscriber to register.
void subscribe(dynamic subscriber);
/// Waits for an event to occur.
///
/// Platform-specific: Provides event waiting functionality.
///
/// Parameters:
/// - [event]: Event to wait for.
/// - [payload]: Optional payload to dispatch.
Future<dynamic> until(dynamic event, [dynamic payload]);
/// Dispatches an event.
///
/// Laravel-compatible: Dispatches events, with platform-specific
/// extensions for halting and payload handling.
///
/// Parameters:
/// - [event]: Event to dispatch.
/// - [payload]: Optional event payload.
/// - [halt]: Whether to halt after first handler.
Future<dynamic> dispatch(dynamic event, [dynamic payload, bool? halt]);
/// Gets registered listeners.
///
/// Laravel-compatible: Retrieves event listeners.
///
/// Parameters:
/// - [eventName]: Name of the event.
List<Function> getListeners(String eventName);
/// Removes an event listener.
///
/// Laravel-compatible: Removes event listeners.
///
/// Parameters:
/// - [event]: Event to remove listener for.
void forget(String event);
/// Removes pushed event listeners.
///
/// Platform-specific: Cleans up delayed event listeners.
void forgetPushed();
/// Sets queue resolver.
///
/// Laravel-compatible: Configures queue integration.
///
/// Parameters:
/// - [resolver]: Queue resolver function.
void setQueueResolver(Function resolver);
/// Sets transaction manager resolver.
///
/// Laravel-compatible: Configures transaction integration.
///
/// Parameters:
/// - [resolver]: Transaction manager resolver function.
void setTransactionManagerResolver(Function resolver);
/// Gets raw event listeners.
///
/// Platform-specific: Provides access to raw listener data.
Map<String, List<Function>> getRawListeners();
}
/// Contract for event subscribers.
///
/// Laravel-compatible: Defines how event subscribers register
/// their event handling methods.
abstract class EventSubscriberContract {
/// Subscribes to events.
///
/// Laravel-compatible: Returns event handler mappings.
///
/// Returns a map of event types to handler functions.
Map<Type, Function> subscribe();
}
/// Marker interface for broadcastable events.
///
/// Laravel-compatible: Events implementing this interface will be broadcast
/// across the application.
abstract class ShouldBroadcast {
/// Gets channels to broadcast on.
///
/// Laravel-compatible: Defines broadcast channels.
List<String> broadcastOn();
/// Gets event name for broadcasting.
///
/// Laravel-compatible: Defines broadcast event name.
String broadcastAs() => runtimeType.toString();
/// Gets broadcast data.
///
/// Laravel-compatible: Defines broadcast payload.
Map<String, dynamic> get broadcastWith => {};
}
/// Marker interface for queueable events.
///
/// Laravel-compatible: Events implementing this interface will be processed
/// through the queue system.
abstract class ShouldQueue {
/// Gets the queue name.
///
/// Laravel-compatible: Defines target queue.
String get queue => 'default';
/// Gets the processing delay.
///
/// Laravel-compatible: Defines queue delay.
Duration? get delay => null;
/// Gets maximum retry attempts.
///
/// Laravel-compatible: Defines retry limit.
int get tries => 1;
}
/// Marker interface for encrypted events.
///
/// Laravel-compatible: Events implementing this interface will be encrypted
/// before being stored or transmitted.
abstract class ShouldBeEncrypted {
/// Whether the event should be encrypted.
///
/// Laravel-compatible: Controls event encryption.
bool get shouldBeEncrypted => true;
}
/// Marker interface for events that should dispatch after commit.
///
/// Laravel-compatible: Events implementing this interface will only be dispatched
/// after the current database transaction commits.
abstract class ShouldDispatchAfterCommit {
/// Whether to dispatch after commit.
///
/// Laravel-compatible: Controls transaction-based dispatch.
bool get afterCommit => true;
}

View file

@ -0,0 +1,2 @@
/// Events package contracts
export 'event_dispatcher_contract.dart';

View file

@ -0,0 +1,2 @@
/// HTTP package contracts
export 'http_contract.dart';

View file

@ -0,0 +1,299 @@
import 'package:meta/meta.dart';
/// Contract for HTTP requests.
///
/// Laravel-compatible: Core request functionality matching Laravel's Request
/// interface, with platform-specific stream handling.
@sealed
abstract class RequestContract {
/// Gets the request method.
///
/// Laravel-compatible: HTTP method accessor.
String get method;
/// Gets the request URI.
///
/// Laravel-compatible: Request URI using Dart's Uri class.
Uri get uri;
/// Gets request headers.
///
/// Laravel-compatible: Header access with platform-specific
/// multi-value support.
Map<String, List<String>> get headers;
/// Gets query parameters.
///
/// Laravel-compatible: Query parameter access.
Map<String, String> get query;
/// Gets POST data.
///
/// Laravel-compatible: POST data access.
Map<String, dynamic> get post;
/// Gets cookies.
///
/// Laravel-compatible: Cookie access.
Map<String, String> get cookies;
/// Gets uploaded files.
///
/// Laravel-compatible: File upload handling with
/// platform-specific contract.
Map<String, UploadedFileContract> get files;
/// Gets the request body.
///
/// Platform-specific: Stream-based body access.
Stream<List<int>> get body;
/// Gets a request header.
///
/// Laravel-compatible: Single header access.
String? header(String name, [String? defaultValue]);
/// Gets a query parameter.
///
/// Laravel-compatible: Single query parameter access.
String? query_(String name, [String? defaultValue]);
/// Gets a POST value.
///
/// Laravel-compatible: Single POST value access.
dynamic post_(String name, [dynamic defaultValue]);
/// Gets a cookie value.
///
/// Laravel-compatible: Single cookie access.
String? cookie(String name, [String? defaultValue]);
/// Gets an uploaded file.
///
/// Laravel-compatible: Single file access.
UploadedFileContract? file(String name);
/// Gets all input data (query + post).
///
/// Laravel-compatible: Combined input access.
Map<String, dynamic> all();
/// Gets input value from any source.
///
/// Laravel-compatible: Universal input access.
dynamic input(String name, [dynamic defaultValue]);
/// Checks if input exists.
///
/// Laravel-compatible: Input existence check.
bool has(String name);
/// Gets the raw request body as string.
///
/// Platform-specific: Async text body access.
Future<String> text();
/// Gets the request body as JSON.
///
/// Platform-specific: Async JSON body access.
Future<dynamic> json();
}
/// Contract for HTTP responses.
///
/// Laravel-compatible: Core response functionality matching Laravel's Response
/// interface, with platform-specific async features.
@sealed
abstract class ResponseContract {
/// Gets response headers.
///
/// Laravel-compatible: Header access with platform-specific
/// multi-value support.
Map<String, List<String>> get headers;
/// Gets the status code.
///
/// Laravel-compatible: Status code accessor.
int get status;
/// Sets the status code.
///
/// Laravel-compatible: Status code mutator.
set status(int value);
/// Sets a response header.
///
/// Laravel-compatible: Single header setting.
void header(String name, String value);
/// Sets multiple headers.
///
/// Laravel-compatible: Bulk header setting.
void headers_(Map<String, String> headers);
/// Sets a cookie.
///
/// Laravel-compatible: Cookie setting with platform-specific
/// security options.
void cookie(
String name,
String value, {
Duration? maxAge,
DateTime? expires,
String? domain,
String? path,
bool secure = false,
bool httpOnly = false,
String? sameSite,
});
/// Writes response body content.
///
/// Laravel-compatible: Content writing.
void write(dynamic content);
/// Sends JSON response.
///
/// Laravel-compatible: JSON response.
void json(dynamic data);
/// Sends file download.
///
/// Laravel-compatible: File download with platform-specific
/// async handling.
Future<void> download(String path, [String? name]);
/// Redirects to another URL.
///
/// Laravel-compatible: Redirect response.
void redirect(String url, [int status = 302]);
/// Sends the response.
///
/// Platform-specific: Async response sending.
Future<void> send();
}
/// Contract for uploaded files.
///
/// Laravel-compatible: File upload handling matching Laravel's UploadedFile
/// interface, with platform-specific async operations.
@sealed
abstract class UploadedFileContract {
/// Gets the original client filename.
///
/// Laravel-compatible: Original filename.
String get filename;
/// Gets the file MIME type.
///
/// Laravel-compatible: MIME type.
String get mimeType;
/// Gets the file size in bytes.
///
/// Laravel-compatible: File size.
int get size;
/// Gets temporary file path.
///
/// Laravel-compatible: Temporary storage.
String get path;
/// Moves file to new location.
///
/// Laravel-compatible: File movement with platform-specific
/// async handling.
Future<void> moveTo(String path);
/// Gets file contents as bytes.
///
/// Platform-specific: Async binary content access.
Future<List<int>> bytes();
/// Gets file contents as string.
///
/// Platform-specific: Async text content access.
Future<String> text();
}
/// Contract for HTTP middleware.
///
/// Laravel-compatible: Middleware functionality matching Laravel's Middleware
/// interface, with platform-specific async handling.
@sealed
abstract class MiddlewareContract {
/// Handles the request.
///
/// Laravel-compatible: Middleware handling with platform-specific
/// async processing.
///
/// Parameters:
/// - [request]: The incoming request.
/// - [next]: Function to pass to next middleware.
Future<ResponseContract> handle(RequestContract request,
Future<ResponseContract> Function(RequestContract) next);
}
/// Contract for HTTP kernel.
///
/// Laravel-compatible: HTTP kernel functionality matching Laravel's HttpKernel
/// interface, with platform-specific async processing.
@sealed
abstract class HttpKernelContract {
/// Gets global middleware.
///
/// Laravel-compatible: Global middleware list.
List<MiddlewareContract> get middleware;
/// Gets middleware groups.
///
/// Laravel-compatible: Middleware grouping.
Map<String, List<MiddlewareContract>> get middlewareGroups;
/// Gets route middleware.
///
/// Laravel-compatible: Route middleware mapping.
Map<String, MiddlewareContract> get routeMiddleware;
/// Handles an HTTP request.
///
/// Laravel-compatible: Request handling with platform-specific
/// async processing.
Future<ResponseContract> handle(RequestContract request);
/// Terminates the request/response cycle.
///
/// Laravel-compatible: Request termination with platform-specific
/// async processing.
Future<ResponseContract> terminate(
RequestContract request, ResponseContract response);
}
/// Contract for HTTP context.
///
/// Platform-specific: Provides request context beyond Laravel's
/// standard request handling.
@sealed
abstract class HttpContextContract {
/// Gets the current request.
RequestContract get request;
/// Gets the current response.
ResponseContract get response;
/// Gets context attributes.
Map<String, dynamic> get attributes;
/// Gets a context attribute.
T? getAttribute<T>(String key);
/// Sets a context attribute.
void setAttribute(String key, dynamic value);
/// Gets the route parameters.
Map<String, dynamic> get routeParams;
/// Gets a route parameter.
T? getRouteParam<T>(String name);
}

View file

@ -0,0 +1,2 @@
/// Model package contracts
export 'model_contract.dart';

View file

@ -0,0 +1,148 @@
import 'package:meta/meta.dart';
/// Contract for base model functionality.
///
/// Laravel-compatible: Provides core model functionality similar to Laravel's
/// Model class, adapted for Dart's type system and patterns.
@sealed
abstract class ModelContract {
/// Gets the model's unique identifier.
///
/// Laravel-compatible: Primary key accessor.
/// Extended with nullable String type for flexibility.
String? get id;
/// Sets the model's unique identifier.
///
/// Laravel-compatible: Primary key mutator.
/// Extended with nullable String type for flexibility.
set id(String? value);
/// Gets the creation timestamp.
///
/// Laravel-compatible: Created at timestamp accessor.
/// Uses Dart's DateTime instead of Carbon.
DateTime? get createdAt;
/// Sets the creation timestamp.
///
/// Laravel-compatible: Created at timestamp mutator.
/// Uses Dart's DateTime instead of Carbon.
set createdAt(DateTime? value);
/// Gets the last update timestamp.
///
/// Laravel-compatible: Updated at timestamp accessor.
/// Uses Dart's DateTime instead of Carbon.
DateTime? get updatedAt;
/// Sets the last update timestamp.
///
/// Laravel-compatible: Updated at timestamp mutator.
/// Uses Dart's DateTime instead of Carbon.
set updatedAt(DateTime? value);
/// Gets the ID as an integer.
///
/// Platform-specific: Provides integer ID conversion.
/// Returns -1 if ID is null or not a valid integer.
int get idAsInt;
/// Gets the ID as a string.
///
/// Platform-specific: Provides string ID conversion.
/// Returns empty string if ID is null.
String get idAsString;
}
/// Contract for auditable model functionality.
///
/// Laravel-compatible: Similar to Laravel's auditable trait,
/// providing user tracking for model changes.
@sealed
abstract class AuditableModelContract extends ModelContract {
/// Gets the ID of user who created the record.
///
/// Laravel-compatible: Created by user tracking.
/// Uses String ID instead of user model reference.
String? get createdBy;
/// Sets the ID of user who created the record.
///
/// Laravel-compatible: Created by user tracking.
/// Uses String ID instead of user model reference.
set createdBy(String? value);
/// Gets the ID of user who last updated the record.
///
/// Laravel-compatible: Updated by user tracking.
/// Uses String ID instead of user model reference.
String? get updatedBy;
/// Sets the ID of user who last updated the record.
///
/// Laravel-compatible: Updated by user tracking.
/// Uses String ID instead of user model reference.
set updatedBy(String? value);
}
/// Optional contract for model serialization.
///
/// Laravel-compatible: Similar to Laravel's serialization features,
/// adapted for Dart's type system.
@sealed
abstract class SerializableModelContract {
/// Converts model to a map.
///
/// Laravel-compatible: Similar to toArray() method.
Map<String, dynamic> toMap();
/// Creates model from a map.
///
/// Laravel-compatible: Similar to fill() method.
void fromMap(Map<String, dynamic> map);
}
/// Optional contract for model validation.
///
/// Platform-specific: Provides built-in validation support,
/// inspired by Laravel's validation but adapted for Dart.
@sealed
abstract class ValidatableModelContract {
/// Validates the model.
///
/// Platform-specific: Returns validation errors if invalid.
Map<String, List<String>>? validate();
/// Gets validation rules.
///
/// Platform-specific: Defines validation rules.
Map<String, List<String>> get rules;
/// Gets custom error messages.
///
/// Platform-specific: Defines custom validation messages.
Map<String, String> get messages;
}
/// Optional contract for model events.
///
/// Laravel-compatible: Similar to Laravel's model events,
/// adapted for Dart's event system.
@sealed
abstract class ObservableModelContract {
/// Gets the event name.
///
/// Laravel-compatible: Defines event identifier.
String get eventName;
/// Gets the event timestamp.
///
/// Platform-specific: Adds timestamp tracking to events.
DateTime get eventTimestamp;
/// Gets event data.
///
/// Laravel-compatible: Provides event payload.
Map<String, dynamic> get eventData;
}

View file

@ -0,0 +1,2 @@
/// Pipeline package contracts
export 'pipeline_contract.dart';

View file

@ -0,0 +1,127 @@
import 'package:meta/meta.dart';
/// Contract for a pipe that processes objects in a pipeline.
///
/// Laravel-compatible: Core pipe functionality matching Laravel's
/// pipe interface, with platform-specific async handling.
@sealed
abstract class PipeContract {
/// Handles the passable object.
///
/// Laravel-compatible: Core pipe handling with platform-specific
/// async processing.
///
/// Parameters:
/// - [passable]: The object being passed through the pipeline.
/// - [next]: Function to pass the object to the next pipe.
///
/// Returns the processed object, possibly modified.
Future<dynamic> handle(
dynamic passable, Future<dynamic> Function(dynamic) next);
}
/// Contract for a pipeline that processes objects through a series of pipes.
///
/// Laravel-compatible: Core pipeline functionality matching Laravel's
/// Pipeline class, with platform-specific fluent interface.
@sealed
abstract class PipelineContract {
/// Sets the object to be passed through the pipeline.
///
/// Laravel-compatible: Pipeline input setting.
///
/// Parameters:
/// - [passable]: The object to process.
///
/// Returns the pipeline instance for fluent chaining.
PipelineContract send(dynamic passable);
/// Sets the array of pipes to process the object through.
///
/// Laravel-compatible: Pipe configuration with platform-specific
/// flexibility for pipe types.
///
/// Parameters:
/// - [pipes]: The pipes to process the object through.
/// Can be a single pipe or an iterable of pipes.
///
/// Returns the pipeline instance for fluent chaining.
PipelineContract through(dynamic pipes);
/// Adds additional pipes to the pipeline.
///
/// Platform-specific: Additional method for pipe configuration
/// following Laravel's fluent pattern.
///
/// Parameters:
/// - [pipes]: The pipes to add.
/// Can be a single pipe or an iterable of pipes.
///
/// Returns the pipeline instance for fluent chaining.
PipelineContract pipe(dynamic pipes);
/// Sets the method to call on the pipes.
///
/// Laravel-compatible: Method name configuration.
///
/// Parameters:
/// - [method]: The name of the method to call.
///
/// Returns the pipeline instance for fluent chaining.
PipelineContract via(String method);
/// Runs the pipeline with a final destination callback.
///
/// Laravel-compatible: Pipeline execution with platform-specific
/// async processing.
///
/// Parameters:
/// - [destination]: Function to process the final result.
///
/// Returns the processed result.
Future<dynamic> then(dynamic Function(dynamic) destination);
/// Runs the pipeline and returns the result.
///
/// Platform-specific: Direct result access following Laravel's
/// pipeline execution pattern.
///
/// Returns the processed object directly.
Future<dynamic> thenReturn();
}
/// Contract for a pipeline hub that manages multiple pipelines.
///
/// Laravel-compatible: Pipeline management functionality matching
/// Laravel's pipeline hub features.
@sealed
abstract class PipelineHubContract {
/// Gets or creates a pipeline with the given name.
///
/// Laravel-compatible: Named pipeline access.
///
/// Parameters:
/// - [name]: The name of the pipeline.
///
/// Returns the pipeline instance.
PipelineContract pipeline(String name);
/// Sets the default pipes for a pipeline.
///
/// Laravel-compatible: Default pipe configuration.
///
/// Parameters:
/// - [name]: The name of the pipeline.
/// - [pipes]: The default pipes for the pipeline.
void defaults(String name, List<dynamic> pipes);
/// Registers a pipe type with a name.
///
/// Platform-specific: Named pipe type registration following
/// Laravel's service registration pattern.
///
/// Parameters:
/// - [name]: The name to register the pipe type under.
/// - [type]: The pipe type to register.
void registerPipeType(String name, Type type);
}

View file

@ -0,0 +1,2 @@
/// Process package contracts
export 'process_contract.dart';

View file

@ -0,0 +1,251 @@
import 'dart:async';
import 'dart:io';
import 'package:meta/meta.dart';
/// Contract for process management.
///
/// Platform-specific: Provides system process management following Laravel's
/// architectural patterns for resource management and lifecycle control.
@sealed
abstract class ProcessManagerContract {
/// Starts a new process.
///
/// Platform-specific: Creates and starts a new system process with
/// Laravel-style identifier and configuration options.
///
/// Parameters:
/// - [id]: Unique identifier for the process.
/// - [command]: Command to execute.
/// - [arguments]: Command arguments.
/// - [workingDirectory]: Optional working directory.
/// - [environment]: Optional environment variables.
/// - [timeout]: Optional execution timeout.
/// - [tty]: Whether to run in a terminal.
/// - [enableReadError]: Whether to enable error stream reading.
Future<ProcessContract> start(
String id,
String command,
List<String> arguments, {
String? workingDirectory,
Map<String, String>? environment,
Duration? timeout,
bool tty = false,
bool enableReadError = true,
});
/// Gets a running process by ID.
///
/// Platform-specific: Retrieves process by identifier,
/// following Laravel's repository pattern.
ProcessContract? get(String id);
/// Kills a process.
///
/// Platform-specific: Terminates a process with optional signal,
/// following Laravel's resource cleanup patterns.
///
/// Parameters:
/// - [id]: Process ID to kill.
/// - [signal]: Signal to send (default: SIGTERM).
Future<void> kill(String id, {ProcessSignal signal = ProcessSignal.sigterm});
/// Kills all managed processes.
///
/// Platform-specific: Bulk process termination,
/// following Laravel's collection operation patterns.
Future<void> killAll({ProcessSignal signal = ProcessSignal.sigterm});
/// Gets process events stream.
///
/// Platform-specific: Event streaming following Laravel's
/// event broadcasting patterns.
Stream<ProcessEventContract> get events;
/// Runs processes in a pool.
///
/// Platform-specific: Concurrent process execution following
/// Laravel's job queue worker pool patterns.
///
/// Parameters:
/// - [processes]: Processes to run.
/// - [concurrency]: Max concurrent processes.
Future<List<ProcessResultContract>> pool(
List<ProcessContract> processes, {
int concurrency = 5,
});
/// Runs processes in a pipeline.
///
/// Platform-specific: Sequential process execution following
/// Laravel's pipeline pattern.
Future<ProcessResultContract> pipeline(List<ProcessContract> processes);
/// Disposes the manager and all processes.
///
/// Platform-specific: Resource cleanup following Laravel's
/// service provider cleanup patterns.
void dispose();
}
/// Contract for process instances.
///
/// Platform-specific: Defines individual process behavior following
/// Laravel's resource management patterns.
@sealed
abstract class ProcessContract {
/// Gets the process command.
String get command;
/// Gets the process ID.
int? get pid;
/// Gets process start time.
DateTime? get startTime;
/// Gets process end time.
DateTime? get endTime;
/// Gets process output stream.
Stream<List<int>> get output;
/// Gets process error stream.
Stream<List<int>> get errorOutput;
/// Gets process exit code.
Future<int> get exitCode;
/// Whether the process is running.
bool get isRunning;
/// Starts the process.
Future<ProcessContract> start();
/// Runs the process to completion.
Future<ProcessResultContract> run();
/// Runs the process with a timeout.
///
/// Parameters:
/// - [timeout]: Maximum execution time.
///
/// Throws TimeoutException if process exceeds timeout.
Future<ProcessResultContract> runWithTimeout(Duration timeout);
/// Writes input to the process.
Future<void> write(String input);
/// Writes multiple lines to the process.
Future<void> writeLines(List<String> lines);
/// Kills the process.
Future<void> kill({ProcessSignal signal = ProcessSignal.sigterm});
/// Sends a signal to the process.
bool sendSignal(ProcessSignal signal);
/// Gets process output as string.
Future<String> get outputAsString;
/// Gets process error output as string.
Future<String> get errorOutputAsString;
/// Disposes the process.
Future<void> dispose();
}
/// Contract for process results.
///
/// Platform-specific: Defines process execution results following
/// Laravel's response/result patterns.
@sealed
abstract class ProcessResultContract {
/// Gets the process ID.
int get pid;
/// Gets the exit code.
int get exitCode;
/// Gets the process output.
String get output;
/// Gets the process error output.
String get errorOutput;
/// Gets string representation.
@override
String toString() {
return 'ProcessResult(pid: $pid, exitCode: $exitCode, output: ${output.length} chars, errorOutput: ${errorOutput.length} chars)';
}
}
/// Contract for process events.
///
/// Platform-specific: Defines process lifecycle events following
/// Laravel's event system patterns.
@sealed
abstract class ProcessEventContract {
/// Gets the process ID.
String get id;
/// Gets the event timestamp.
DateTime get timestamp;
}
/// Contract for process started events.
///
/// Platform-specific: Defines process start event following
/// Laravel's event naming and structure patterns.
@sealed
abstract class ProcessStartedEventContract extends ProcessEventContract {
/// Gets the started process.
ProcessContract get process;
@override
String toString() =>
'ProcessStartedEvent(id: $id, command: ${process.command})';
}
/// Contract for process exited events.
///
/// Platform-specific: Defines process exit event following
/// Laravel's event naming and structure patterns.
@sealed
abstract class ProcessExitedEventContract extends ProcessEventContract {
/// Gets the exit code.
int get exitCode;
@override
String toString() => 'ProcessExitedEvent(id: $id, exitCode: $exitCode)';
}
/// Contract for process pools.
///
/// Platform-specific: Defines concurrent process execution following
/// Laravel's worker pool patterns.
@sealed
abstract class ProcessPoolContract {
/// Gets maximum concurrent processes.
int get concurrency;
/// Gets active processes.
List<ProcessContract> get active;
/// Gets pending processes.
List<ProcessContract> get pending;
/// Runs processes in the pool.
Future<List<ProcessResultContract>> run(List<ProcessContract> processes);
}
/// Contract for process pipelines.
///
/// Platform-specific: Defines sequential process execution following
/// Laravel's pipeline pattern.
@sealed
abstract class ProcessPipelineContract {
/// Gets pipeline processes.
List<ProcessContract> get processes;
/// Runs the pipeline.
Future<ProcessResultContract> run();
}

View file

@ -0,0 +1,2 @@
/// Queue package contracts
export 'queue_contract.dart';

View file

@ -0,0 +1,284 @@
import 'package:meta/meta.dart';
/// Contract for queue operations.
///
/// Laravel-compatible: Core queue functionality matching Laravel's Queue
/// interface, adapted for Dart's type system and async patterns.
@sealed
abstract class QueueContract {
/// Pushes a job onto the queue.
///
/// Laravel-compatible: Core push method.
/// Uses dynamic job type for flexibility.
Future<String> push(dynamic job, [String? queue]);
/// Pushes a job onto a specific queue.
///
/// Laravel-compatible: Queue-specific push.
/// Uses dynamic job type for flexibility.
Future<String> pushOn(String queue, dynamic job);
/// Pushes a delayed job onto the queue.
///
/// Laravel-compatible: Delayed job push.
/// Uses Duration instead of DateTime/Carbon.
Future<String> later(Duration delay, dynamic job, [String? queue]);
/// Pushes a delayed job onto a specific queue.
///
/// Laravel-compatible: Queue-specific delayed push.
/// Uses Duration instead of DateTime/Carbon.
Future<String> laterOn(String queue, Duration delay, dynamic job);
/// Pushes multiple jobs onto the queue.
///
/// Laravel-compatible: Bulk job push.
/// Uses dynamic job type for flexibility.
Future<void> bulk(List<dynamic> jobs, [String? queue]);
/// Gets the next job from the queue.
///
/// Laravel-compatible: Job pop operation.
Future<JobContract?> pop([String? queue]);
/// Creates a job batch.
///
/// Laravel-compatible: Batch creation.
BatchContract batch(List<JobContract> jobs);
/// Gets a queue connection.
///
/// Laravel-compatible: Connection retrieval.
QueueConnectionContract connection([String? name]);
}
/// Contract for queue jobs.
///
/// Laravel-compatible: Core job interface matching Laravel's Job
/// contract, with platform-specific extensions.
@sealed
abstract class JobContract {
/// Gets the job ID.
///
/// Laravel-compatible: Job identifier.
String get id;
/// Gets the job payload.
///
/// Laravel-compatible: Job data.
Map<String, dynamic> get payload;
/// Gets the number of attempts.
///
/// Laravel-compatible: Attempt tracking.
int get attempts;
/// Gets the maximum number of tries.
///
/// Laravel-compatible: Retry limit.
int get tries;
/// Gets the job timeout in seconds.
///
/// Laravel-compatible: Timeout configuration.
int get timeout;
/// Gets the queue name.
///
/// Laravel-compatible: Queue designation.
String? get queue;
/// Gets the job delay.
///
/// Laravel-compatible: Delay configuration.
/// Uses Duration instead of DateTime/Carbon.
Duration? get delay;
/// Whether the job should be encrypted.
///
/// Platform-specific: Adds encryption support.
bool get shouldBeEncrypted;
/// Whether to dispatch after commit.
///
/// Laravel-compatible: Transaction support.
bool get afterCommit;
/// Executes the job.
///
/// Laravel-compatible: Core job execution.
Future<void> handle();
/// Handles job failure.
///
/// Laravel-compatible: Failure handling.
Future<void> failed([Exception? exception]);
/// Releases the job back to the queue.
///
/// Laravel-compatible: Job release.
/// Uses Duration instead of DateTime/Carbon.
Future<void> release([Duration? delay]);
/// Deletes the job.
///
/// Laravel-compatible: Job deletion.
Future<void> delete();
}
/// Contract for job batches.
///
/// Laravel-compatible: Batch operations matching Laravel's batch
/// functionality, with platform-specific extensions.
@sealed
abstract class BatchContract {
/// Gets the batch ID.
///
/// Laravel-compatible: Batch identifier.
String get id;
/// Gets the jobs in the batch.
///
/// Laravel-compatible: Batch jobs.
List<JobContract> get jobs;
/// Adds jobs to the batch.
///
/// Laravel-compatible: Job addition.
void add(List<JobContract> jobs);
/// Dispatches the batch.
///
/// Laravel-compatible: Batch dispatch.
Future<void> dispatch();
/// Allows failures in the batch.
///
/// Laravel-compatible: Failure configuration.
BatchContract allowFailures();
/// Sets the batch name.
///
/// Laravel-compatible: Batch naming.
BatchContract name(String name);
/// Adds a callback when all jobs finish.
///
/// Laravel-compatible: Success callback.
BatchContract then(void Function(BatchContract) callback);
/// Adds a callback when the batch fails.
///
/// Laravel-compatible: Error callback.
BatchContract onError(void Function(BatchContract, dynamic) callback);
/// Gets the batch progress.
///
/// Platform-specific: Progress tracking.
double get progress;
/// Gets finished job count.
///
/// Platform-specific: Completion tracking.
int get finished;
/// Gets failed job count.
///
/// Platform-specific: Failure tracking.
int get failed;
/// Gets pending job count.
///
/// Platform-specific: Pending tracking.
int get pending;
/// Gets total job count.
///
/// Platform-specific: Size tracking.
int get total;
}
/// Contract for queue connections.
///
/// Laravel-compatible: Connection management matching Laravel's
/// queue connection functionality.
@sealed
abstract class QueueConnectionContract {
/// Gets the connection name.
///
/// Laravel-compatible: Connection identifier.
String get name;
/// Gets the connection driver.
///
/// Laravel-compatible: Driver type.
String get driver;
/// Gets the connection config.
///
/// Laravel-compatible: Configuration access.
Map<String, dynamic> get config;
/// Pushes a job onto the queue.
///
/// Laravel-compatible: Job push.
Future<String> push(dynamic job, [String? queue]);
/// Gets the next job from the queue.
///
/// Laravel-compatible: Job pop.
Future<JobContract?> pop([String? queue]);
/// Gets queue size.
///
/// Laravel-compatible: Size check.
Future<int> size([String? queue]);
/// Clears the queue.
///
/// Laravel-compatible: Queue clear.
Future<void> clear([String? queue]);
/// Pauses job processing.
///
/// Laravel-compatible: Processing pause.
Future<void> pause([String? queue]);
/// Resumes job processing.
///
/// Laravel-compatible: Processing resume.
Future<void> resume([String? queue]);
}
/// Contract for queue manager.
///
/// Laravel-compatible: Manager functionality matching Laravel's
/// queue manager interface.
@sealed
abstract class QueueManagerContract {
/// Gets a queue connection.
///
/// Laravel-compatible: Connection retrieval.
QueueConnectionContract connection([String? name]);
/// Gets the default connection name.
///
/// Laravel-compatible: Default connection.
String get defaultConnection;
/// Sets the default connection name.
///
/// Laravel-compatible: Default connection.
set defaultConnection(String name);
/// Gets connection configuration.
///
/// Laravel-compatible: Config access.
Map<String, dynamic> getConfig(String name);
/// Extends available drivers.
///
/// Laravel-compatible: Driver extension.
void extend(String driver,
QueueConnectionContract Function(Map<String, dynamic>) callback);
}

View file

@ -0,0 +1,2 @@
/// Reflection package contracts
export 'reflector_contract.dart';

View file

@ -0,0 +1,147 @@
/*
* This file is part of the Protevus Platform.
*
* (C) Protevus <developers@protevus.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/// Contract for reflected type parameters
abstract class ReflectedTypeParameterContract {
/// Gets the name of the type parameter
String get name;
}
/// Contract for reflected types
abstract class ReflectedTypeContract {
/// Gets the name of the type
String get name;
/// Gets the type parameters if the type is generic
List<ReflectedTypeParameterContract> get typeParameters;
/// Gets the actual Dart type being reflected
Type get reflectedType;
/// Checks if this type is assignable to another type
bool isAssignableTo(ReflectedTypeContract? other);
/// Creates a new instance of this type
ReflectedInstanceContract newInstance(
String constructorName, List positionalArguments,
[Map<String, dynamic> namedArguments = const {},
List<Type> typeArguments = const []]);
}
/// Contract for reflected parameters
abstract class ReflectedParameterContract {
/// Gets the parameter name
String get name;
/// Gets the parameter annotations
List<ReflectedInstanceContract> get annotations;
/// Gets the parameter type
ReflectedTypeContract get type;
/// Whether the parameter is required
bool get isRequired;
/// Whether the parameter is named
bool get isNamed;
}
/// Contract for reflected functions
abstract class ReflectedFunctionContract {
/// Gets the function name
String get name;
/// Gets the function's type parameters
List<ReflectedTypeParameterContract> get typeParameters;
/// Gets the function's annotations
List<ReflectedInstanceContract> get annotations;
/// Gets the function's return type
ReflectedTypeContract? get returnType;
/// Gets the function's parameters
List<ReflectedParameterContract> get parameters;
/// Whether the function is a getter
bool get isGetter;
/// Whether the function is a setter
bool get isSetter;
/// Invokes the function
ReflectedInstanceContract invoke(Invocation invocation);
}
/// Contract for reflected declarations
abstract class ReflectedDeclarationContract {
/// Gets the declaration name
String get name;
/// Whether the declaration is static
bool get isStatic;
/// Gets the associated function if any
ReflectedFunctionContract? get function;
}
/// Contract for reflected classes
abstract class ReflectedClassContract extends ReflectedTypeContract {
/// Gets the class annotations
List<ReflectedInstanceContract> get annotations;
/// Gets the class constructors
List<ReflectedFunctionContract> get constructors;
/// Gets the class declarations
List<ReflectedDeclarationContract> get declarations;
}
/// Contract for reflected instances
abstract class ReflectedInstanceContract {
/// Gets the instance type
ReflectedTypeContract get type;
/// Gets the instance class
ReflectedClassContract get clazz;
/// Gets the actual instance being reflected
Object? get reflectee;
/// Gets a field value
ReflectedInstanceContract getField(String name);
}
/// Core reflector contract for type introspection.
///
/// This contract defines the interface for reflection capabilities,
/// allowing runtime inspection and manipulation of types, classes,
/// functions, and instances.
abstract class ReflectorContract {
/// Gets the name from a symbol
String? getName(Symbol symbol);
/// Reflects a class type
ReflectedClassContract? reflectClass(Type clazz);
/// Reflects a function
ReflectedFunctionContract? reflectFunction(Function function);
/// Reflects a type
ReflectedTypeContract? reflectType(Type type);
/// Reflects an instance
ReflectedInstanceContract? reflectInstance(Object object);
/// Reflects the Future of a type
///
/// Throws:
/// - UnsupportedError if dart:mirrors is not available
ReflectedTypeContract reflectFutureOf(Type type);
}

View file

@ -0,0 +1,2 @@
/// Routing package contracts
export 'routing_contract.dart';

View file

@ -0,0 +1,260 @@
import 'package:meta/meta.dart';
/// Contract for router functionality.
///
/// Laravel-compatible: Core routing functionality matching Laravel's Router
/// interface, with platform-specific generic type support.
@sealed
abstract class RouterContract<T> {
/// Adds a route that responds to any HTTP method.
///
/// Laravel-compatible: Any-method route registration.
RouteContract<T> any(String path, T handler,
{Iterable<T> middleware = const []});
/// Adds a route that responds to GET requests.
///
/// Laravel-compatible: GET route registration.
RouteContract<T> get(String path, T handler,
{Iterable<T> middleware = const []});
/// Adds a route that responds to POST requests.
///
/// Laravel-compatible: POST route registration.
RouteContract<T> post(String path, T handler,
{Iterable<T> middleware = const []});
/// Adds a route that responds to PUT requests.
///
/// Laravel-compatible: PUT route registration.
RouteContract<T> put(String path, T handler,
{Iterable<T> middleware = const []});
/// Adds a route that responds to DELETE requests.
///
/// Laravel-compatible: DELETE route registration.
RouteContract<T> delete(String path, T handler,
{Iterable<T> middleware = const []});
/// Adds a route that responds to PATCH requests.
///
/// Laravel-compatible: PATCH route registration.
RouteContract<T> patch(String path, T handler,
{Iterable<T> middleware = const []});
/// Adds a route that responds to OPTIONS requests.
///
/// Laravel-compatible: OPTIONS route registration.
RouteContract<T> options(String path, T handler,
{Iterable<T> middleware = const []});
/// Creates a route group with shared attributes.
///
/// Laravel-compatible: Route grouping with platform-specific
/// callback-based configuration.
///
/// Parameters:
/// - [path]: The prefix path for the group.
/// - [callback]: Function to define routes within the group.
/// - [middleware]: Middleware to apply to all routes in the group.
void group(String path, void Function(RouterContract<T> router) callback,
{Iterable<T> middleware = const []});
/// Mounts another router at a path prefix.
///
/// Platform-specific: Provides router composition functionality.
///
/// Parameters:
/// - [path]: The path to mount at.
/// - [router]: The router to mount.
void mount(String path, RouterContract<T> router);
/// Resolves a route for a request.
///
/// Laravel-compatible: Route matching with platform-specific
/// match result contract.
///
/// Parameters:
/// - [method]: The HTTP method.
/// - [path]: The request path.
RouteMatchContract<T>? resolve(String method, String path);
}
/// Contract for route definitions.
///
/// Laravel-compatible: Route definition interface matching Laravel's Route
/// class, with platform-specific enhancements.
@sealed
abstract class RouteContract<T> {
/// Gets the route path pattern.
///
/// Laravel-compatible: Route URI pattern.
String get path;
/// Gets the HTTP method this route responds to.
///
/// Laravel-compatible: HTTP method.
String get method;
/// Gets the route handler.
///
/// Laravel-compatible: Route action with generic typing.
T get handler;
/// Gets the route middleware.
///
/// Laravel-compatible: Route middleware.
Iterable<T> get middleware;
/// Gets the route name.
///
/// Laravel-compatible: Route name accessor.
String? get name;
/// Sets the route name.
///
/// Laravel-compatible: Route name mutator.
set name(String? value);
/// Gets the route parameters.
///
/// Laravel-compatible: Route parameters.
Map<String, dynamic> get parameters;
/// Makes a URI for this route.
///
/// Laravel-compatible: URL generation.
///
/// Parameters:
/// - [params]: The parameter values to use.
String makeUri(Map<String, dynamic> params);
/// Gets the route's regular expression pattern.
///
/// Platform-specific: Direct access to route pattern.
RegExp get pattern;
/// Whether the route matches a path.
///
/// Platform-specific: Direct path matching.
bool matches(String path);
}
/// Contract for route matching results.
///
/// Platform-specific: Defines detailed match results beyond
/// Laravel's basic route matching.
@sealed
abstract class RouteMatchContract<T> {
/// Gets the matched route.
RouteContract<T> get route;
/// Gets the matched parameters.
Map<String, dynamic> get params;
/// Gets any remaining path after the match.
String get remaining;
/// Gets the full matched path.
String get matched;
}
/// Contract for route parameters.
///
/// Laravel-compatible: Parameter handling matching Laravel's
/// parameter constraints, with platform-specific validation.
@sealed
abstract class RouteParameterContract {
/// Gets the parameter name.
String get name;
/// Gets the parameter pattern.
String? get pattern;
/// Whether the parameter is optional.
bool get isOptional;
/// Gets the default value.
dynamic get defaultValue;
/// Validates a parameter value.
bool validate(String value);
}
/// Contract for route collection.
///
/// Laravel-compatible: Route collection functionality matching
/// Laravel's RouteCollection, with platform-specific enhancements.
@sealed
abstract class RouteCollectionContract<T> {
/// Gets all routes.
///
/// Laravel-compatible: Route listing.
Iterable<RouteContract<T>> get routes;
/// Gets routes by method.
///
/// Laravel-compatible: Method filtering.
Iterable<RouteContract<T>> getByMethod(String method);
/// Gets a route by name.
///
/// Laravel-compatible: Named route lookup.
RouteContract<T>? getByName(String name);
/// Adds a route to the collection.
///
/// Laravel-compatible: Route registration.
void add(RouteContract<T> route);
/// Removes a route from the collection.
///
/// Laravel-compatible: Route removal.
void remove(RouteContract<T> route);
/// Gets routes with a specific middleware.
///
/// Platform-specific: Middleware filtering.
Iterable<RouteContract<T>> getByMiddleware(T middleware);
}
/// Contract for route groups.
///
/// Laravel-compatible: Route grouping functionality matching
/// Laravel's route group features, with platform-specific additions.
@sealed
abstract class RouteGroupContract<T> {
/// Gets the group prefix.
///
/// Laravel-compatible: Group prefix.
String get prefix;
/// Gets the group middleware.
///
/// Laravel-compatible: Group middleware.
Iterable<T> get middleware;
/// Gets the group namespace.
///
/// Laravel-compatible: Group namespace.
String? get namespace;
/// Gets routes in this group.
///
/// Laravel-compatible: Group routes.
Iterable<RouteContract<T>> get routes;
/// Adds a route to the group.
///
/// Laravel-compatible: Route addition with platform-specific
/// middleware support.
RouteContract<T> addRoute(String method, String path, T handler,
{Iterable<T> middleware = const []});
/// Creates a sub-group.
///
/// Laravel-compatible: Nested grouping with platform-specific
/// namespace support.
RouteGroupContract<T> group(String prefix,
{Iterable<T> middleware = const [], String? namespace});
}

View file

@ -0,0 +1,2 @@
/// Support package contracts
export 'support_contract.dart';

View file

@ -0,0 +1,263 @@
import 'package:meta/meta.dart';
/// Contract for service providers.
///
/// Laravel-compatible: Core service provider functionality matching
/// Laravel's ServiceProvider class, adapted for Dart's type system.
@sealed
abstract class ServiceProviderContract {
/// Registers application services.
///
/// Laravel-compatible: Core registration method.
void register();
/// Bootstraps application services.
///
/// Laravel-compatible: Core bootstrap method.
void boot();
/// Gets services provided by this provider.
///
/// Laravel-compatible: Lists provided services.
List<String> provides();
/// Gets events that trigger registration.
///
/// Laravel-compatible: Lists registration triggers.
List<String> when();
/// Whether provider is deferred.
///
/// Laravel-compatible: Controls lazy loading.
bool isDeferred();
/// Gets the application instance.
///
/// Laravel-compatible: Application access.
/// Uses dynamic type for flexibility.
dynamic get app;
/// Sets the application instance.
///
/// Laravel-compatible: Application injection.
/// Uses dynamic type for flexibility.
set app(dynamic value);
/// Gets booting callbacks.
///
/// Laravel-compatible: Boot phase callbacks.
List<Function> get bootingCallbacks;
/// Gets booted callbacks.
///
/// Laravel-compatible: Post-boot callbacks.
List<Function> get bootedCallbacks;
/// Registers a booting callback.
///
/// Laravel-compatible: Boot phase hook.
void booting(Function callback);
/// Registers a booted callback.
///
/// Laravel-compatible: Post-boot hook.
void booted(Function callback);
/// Calls booting callbacks.
///
/// Laravel-compatible: Executes boot phase hooks.
void callBootingCallbacks();
/// Calls booted callbacks.
///
/// Laravel-compatible: Executes post-boot hooks.
void callBootedCallbacks();
/// Merges configuration.
///
/// Laravel-compatible: Config merging.
void mergeConfigFrom(String path, String key);
/// Replaces configuration recursively.
///
/// Laravel-compatible: Deep config replacement.
void replaceConfigRecursivelyFrom(String path, String key);
/// Loads routes from file.
///
/// Laravel-compatible: Route loading.
void loadRoutesFrom(String path);
/// Loads views from directory.
///
/// Laravel-compatible: View loading.
void loadViewsFrom(String path, String namespace);
/// Loads view components.
///
/// Laravel-compatible: Component loading.
void loadViewComponentsAs(String prefix, List<Type> components);
/// Loads translations from directory.
///
/// Laravel-compatible: Translation loading.
void loadTranslationsFrom(String path, String namespace);
/// Loads JSON translations.
///
/// Laravel-compatible: JSON translation loading.
void loadJsonTranslationsFrom(String path);
/// Loads database migrations.
///
/// Laravel-compatible: Migration loading.
void loadMigrationsFrom(dynamic paths);
/// Loads model factories.
///
/// Laravel-compatible: Factory loading.
@Deprecated('Will be removed in a future version.')
void loadFactoriesFrom(dynamic paths);
/// Sets up after resolving listener.
///
/// Laravel-compatible: Resolution hook.
void callAfterResolving(String name, Function callback);
/// Publishes migrations.
///
/// Laravel-compatible: Migration publishing.
void publishesMigrations(List<String> paths, [dynamic groups]);
/// Registers publishable paths.
///
/// Laravel-compatible: Asset publishing.
void registerPublishables(Map<String, String> paths, [dynamic groups]);
/// Legacy method for registering publishables.
///
/// Laravel-compatible: Legacy publish method.
@Deprecated('Use registerPublishables instead')
void publishes(Map<String, String> paths, [dynamic groups]);
/// Initializes publish array.
///
/// Laravel-compatible: Publish setup.
void ensurePublishArrayInitialized(String className);
/// Adds a publish group.
///
/// Laravel-compatible: Group publishing.
void addPublishGroup(String group, Map<String, String> paths);
/// Gets paths to publish.
///
/// Laravel-compatible: Publish path lookup.
Map<String, String> pathsToPublish([String? provider, String? group]);
/// Gets paths for provider or group.
///
/// Laravel-compatible: Provider/group path lookup.
Map<String, String> pathsForProviderOrGroup(String? provider, String? group);
/// Gets paths for provider and group.
///
/// Laravel-compatible: Combined path lookup.
Map<String, String> pathsForProviderAndGroup(String provider, String group);
/// Gets publishable providers.
///
/// Laravel-compatible: Provider listing.
List<String> publishableProviders();
/// Gets publishable migration paths.
///
/// Laravel-compatible: Migration path listing.
List<String> publishableMigrationPaths();
/// Gets publishable groups.
///
/// Laravel-compatible: Group listing.
List<String> publishableGroups();
/// Registers commands.
///
/// Laravel-compatible: Command registration.
void commands(List<Type> commands);
/// Gets default providers.
///
/// Laravel-compatible: Default provider listing.
List<Type> defaultProviders();
/// Adds provider to bootstrap file.
///
/// Laravel-compatible: Provider bootstrapping.
bool addProviderToBootstrapFile(String provider, [String? path]);
/// Registers a singleton.
///
/// Laravel-compatible: Singleton binding with Dart typing.
void singleton<T>(T instance);
/// Registers a factory binding.
///
/// Laravel-compatible: Factory binding with Dart typing.
void bind<T>(T Function(dynamic) factory);
/// Gets a service.
///
/// Laravel-compatible: Service resolution with Dart typing.
T make<T>([Type? type]);
/// Checks if service exists.
///
/// Laravel-compatible: Binding check with Dart typing.
bool has<T>();
/// Registers tagged bindings.
///
/// Laravel-compatible: Tag binding with Dart typing.
void tag(List<Type> abstracts, List<Type> tags);
/// Registers an event listener.
///
/// Laravel-compatible: Event listener registration.
void listen(String event, Function listener);
/// Registers middleware.
///
/// Laravel-compatible: Middleware registration.
void middleware(String name, Function handler);
}
/// Contract for deferrable providers.
///
/// Laravel-compatible: Defines providers that can be loaded
/// on demand rather than at application startup.
@sealed
abstract class DeferrableProviderContract {
/// Gets services provided by this provider.
///
/// Laravel-compatible: Lists deferred services.
List<String> provides();
}
/// Contract for provider static functionality.
///
/// Platform-specific: Provides static helper methods and properties
/// following Laravel's patterns for static configuration.
@sealed
abstract class ServiceProviderStaticContract {
/// Gets publishable migration paths.
static final List<String> publishableMigrationPaths = [];
/// Gets publishable paths.
static final Map<String, Map<String, String>> publishablePaths = {};
/// Gets publishable groups.
static final Map<String, Map<String, String>> publishableGroups = {};
/// Gets publishable provider paths.
static final Map<String, Map<String, String>> publishableProviderPaths = {};
}

View file

@ -0,0 +1,2 @@
/// Testing package contracts
export 'testing_contract.dart';

View file

@ -0,0 +1,302 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:meta/meta.dart';
/// Contract for mock HTTP requests.
///
/// This contract defines how HTTP requests should be mocked
/// for testing purposes.
@sealed
abstract class MockHttpRequestContract
implements HttpRequest, StreamSink<List<int>>, StringSink {
/// Gets the request method.
@override
String get method;
/// Gets the request URI.
@override
Uri get uri;
/// Gets request headers.
@override
HttpHeaders get headers;
/// Gets request cookies.
@override
List<Cookie> get cookies;
/// Gets connection info.
@override
HttpConnectionInfo get connectionInfo;
/// Gets request session.
@override
HttpSession get session;
/// Gets request content length.
@override
int get contentLength;
/// Gets protocol version.
@override
String get protocolVersion;
/// Gets SSL/TLS certificate.
@override
X509Certificate? get certificate;
/// Gets whether connection is persistent.
@override
bool get persistentConnection;
/// Gets requested URI.
@override
Uri get requestedUri;
/// Sets requested URI.
set requestedUri(Uri value);
/// Gets response object.
@override
HttpResponse get response;
}
/// Contract for mock HTTP responses.
///
/// This contract defines how HTTP responses should be mocked
/// for testing purposes.
@sealed
abstract class MockHttpResponseContract
implements HttpResponse, Stream<List<int>> {
/// Gets/sets status code.
@override
int get statusCode;
@override
set statusCode(int value);
/// Gets/sets reason phrase.
@override
String get reasonPhrase;
@override
set reasonPhrase(String value);
/// Gets/sets content length.
@override
int get contentLength;
@override
set contentLength(int value);
/// Gets/sets deadline.
@override
Duration? get deadline;
@override
set deadline(Duration? value);
/// Gets/sets encoding.
@override
Encoding get encoding;
@override
set encoding(Encoding value);
/// Gets/sets persistent connection flag.
@override
bool get persistentConnection;
@override
set persistentConnection(bool value);
/// Gets/sets buffer output flag.
@override
bool get bufferOutput;
@override
set bufferOutput(bool value);
/// Gets response headers.
@override
HttpHeaders get headers;
/// Gets response cookies.
@override
List<Cookie> get cookies;
/// Gets connection info.
@override
HttpConnectionInfo get connectionInfo;
/// Gets done future.
@override
Future get done;
/// Detaches socket.
@override
Future<Socket> detachSocket({bool writeHeaders = true});
/// Redirects to location.
@override
Future redirect(Uri location, {int status = HttpStatus.movedTemporarily});
}
/// Contract for mock HTTP sessions.
///
/// This contract defines how HTTP sessions should be mocked
/// for testing purposes.
@sealed
abstract class MockHttpSessionContract implements HttpSession {
/// Gets session ID.
@override
String get id;
/// Gets/sets whether session is new.
@override
bool get isNew;
@override
set isNew(bool value);
/// Gets session data.
Map<String, dynamic> get data;
/// Gets session value.
@override
dynamic operator [](Object? key);
/// Sets session value.
@override
void operator []=(dynamic key, dynamic value);
/// Removes session value.
@override
dynamic remove(Object? key);
/// Clears all session data.
@override
void clear();
/// Destroys the session.
@override
Future<void> destroy();
}
/// Contract for mock HTTP headers.
///
/// This contract defines how HTTP headers should be mocked
/// for testing purposes.
@sealed
abstract class MockHttpHeadersContract implements HttpHeaders {
/// Gets header value.
@override
String? value(String name);
/// Adds header value.
@override
void add(String name, Object value, {bool preserveHeaderCase = false});
/// Removes header.
@override
void remove(String name, Object value);
/// Removes all headers.
@override
void removeAll(String name);
/// Sets header value.
@override
void set(String name, Object value, {bool preserveHeaderCase = false});
/// Gets header values.
@override
List<String>? operator [](String name);
/// Gets all header names.
@override
List<String> get names;
/// Gets header values.
@override
Iterable<String>? getAll(String name);
/// Clears all headers.
@override
void clear();
/// Gets whether headers are mutable.
@override
bool get mutable;
/// Gets content type.
@override
ContentType? get contentType;
/// Sets content type.
@override
set contentType(ContentType? value);
/// Gets date.
@override
DateTime? get date;
/// Sets date.
@override
set date(DateTime? value);
/// Gets expires date.
@override
DateTime? get expires;
/// Sets expires date.
@override
set expires(DateTime? value);
/// Gets if-modified-since date.
@override
DateTime? get ifModifiedSince;
/// Sets if-modified-since date.
@override
set ifModifiedSince(DateTime? value);
/// Gets host.
@override
String? get host;
/// Sets host.
@override
set host(String? value);
/// Gets port.
@override
int? get port;
/// Sets port.
@override
set port(int? value);
/// Locks headers from modification.
void lock();
/// Gets whether headers are locked.
bool get locked;
}
/// Contract for mock connection info.
///
/// This contract defines how connection info should be mocked
/// for testing purposes.
@sealed
abstract class MockConnectionInfoContract implements HttpConnectionInfo {
/// Gets local address.
@override
InternetAddress get localAddress;
/// Gets local port.
@override
int get localPort;
/// Gets remote address.
@override
InternetAddress get remoteAddress;
/// Gets remote port.
@override
int get remotePort;
}

View file

@ -0,0 +1,402 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
_fe_analyzer_shared:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: "45cfa8471b89fb6643fe9bf51bd7931a76b8f5ec2d65de4fb176dba8d4f22c77"
url: "https://pub.dev"
source: hosted
version: "73.0.0"
_macros:
dependency: transitive
description: dart
source: sdk
version: "0.3.2"
analyzer:
dependency: transitive
description:
name: analyzer
sha256: "4959fec185fe70cce007c57e9ab6983101dbe593d2bf8bbfb4453aaec0cf470a"
url: "https://pub.dev"
source: hosted
version: "6.8.0"
args:
dependency: transitive
description:
name: args
sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6
url: "https://pub.dev"
source: hosted
version: "2.6.0"
async:
dependency: transitive
description:
name: async
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
url: "https://pub.dev"
source: hosted
version: "2.12.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
collection:
dependency: transitive
description:
name: collection
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://pub.dev"
source: hosted
version: "1.19.1"
convert:
dependency: transitive
description:
name: convert
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
url: "https://pub.dev"
source: hosted
version: "3.1.2"
coverage:
dependency: transitive
description:
name: coverage
sha256: "4b03e11f6d5b8f6e5bb5e9f7889a56fe6c5cbe942da5378ea4d4d7f73ef9dfe5"
url: "https://pub.dev"
source: hosted
version: "1.11.0"
crypto:
dependency: transitive
description:
name: crypto
sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
url: "https://pub.dev"
source: hosted
version: "3.0.6"
file:
dependency: transitive
description:
name: file
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.dev"
source: hosted
version: "7.0.1"
frontend_server_client:
dependency: transitive
description:
name: frontend_server_client
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
url: "https://pub.dev"
source: hosted
version: "4.0.0"
glob:
dependency: transitive
description:
name: glob
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
url: "https://pub.dev"
source: hosted
version: "3.2.1"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "76d306a1c3afb33fe82e2bbacad62a61f409b5634c915fceb0d799de1a913360"
url: "https://pub.dev"
source: hosted
version: "4.1.1"
io:
dependency: transitive
description:
name: io
sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
url: "https://pub.dev"
source: hosted
version: "1.0.4"
js:
dependency: transitive
description:
name: js
sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf
url: "https://pub.dev"
source: hosted
version: "0.7.1"
lints:
dependency: "direct dev"
description:
name: lints
sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
logging:
dependency: transitive
description:
name: logging
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
url: "https://pub.dev"
source: hosted
version: "1.3.0"
macros:
dependency: transitive
description:
name: macros
sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536"
url: "https://pub.dev"
source: hosted
version: "0.1.2-main.4"
matcher:
dependency: transitive
description:
name: matcher
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
url: "https://pub.dev"
source: hosted
version: "0.12.16+1"
meta:
dependency: "direct main"
description:
name: meta
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
url: "https://pub.dev"
source: hosted
version: "1.16.0"
mime:
dependency: transitive
description:
name: mime
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
node_preamble:
dependency: transitive
description:
name: node_preamble
sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db"
url: "https://pub.dev"
source: hosted
version: "2.0.2"
package_config:
dependency: transitive
description:
name: package_config
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
path:
dependency: transitive
description:
name: path
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
url: "https://pub.dev"
source: hosted
version: "1.9.1"
pool:
dependency: transitive
description:
name: pool
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
url: "https://pub.dev"
source: hosted
version: "1.5.1"
pub_semver:
dependency: transitive
description:
name: pub_semver
sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
shelf:
dependency: transitive
description:
name: shelf
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
url: "https://pub.dev"
source: hosted
version: "1.4.2"
shelf_packages_handler:
dependency: transitive
description:
name: shelf_packages_handler
sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e"
url: "https://pub.dev"
source: hosted
version: "3.0.2"
shelf_static:
dependency: transitive
description:
name: shelf_static
sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3
url: "https://pub.dev"
source: hosted
version: "1.1.3"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
source_map_stack_trace:
dependency: transitive
description:
name: source_map_stack_trace
sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b
url: "https://pub.dev"
source: hosted
version: "2.1.2"
source_maps:
dependency: transitive
description:
name: source_maps
sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703"
url: "https://pub.dev"
source: hosted
version: "0.10.12"
source_span:
dependency: transitive
description:
name: source_span
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
source: hosted
version: "1.10.0"
stack_trace:
dependency: transitive
description:
name: stack_trace
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
url: "https://pub.dev"
source: hosted
version: "1.12.0"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
url: "https://pub.dev"
source: hosted
version: "2.1.2"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "0bd04f5bb74fcd6ff0606a888a30e917af9bd52820b178eaa464beb11dca84b6"
url: "https://pub.dev"
source: hosted
version: "1.4.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
url: "https://pub.dev"
source: hosted
version: "1.2.1"
test:
dependency: "direct dev"
description:
name: test
sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f"
url: "https://pub.dev"
source: hosted
version: "1.25.8"
test_api:
dependency: transitive
description:
name: test_api
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
url: "https://pub.dev"
source: hosted
version: "0.7.3"
test_core:
dependency: transitive
description:
name: test_core
sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d"
url: "https://pub.dev"
source: hosted
version: "0.6.5"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.dev"
source: hosted
version: "1.4.0"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
url: "https://pub.dev"
source: hosted
version: "14.3.1"
watcher:
dependency: transitive
description:
name: watcher
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
web:
dependency: transitive
description:
name: web
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
url: "https://pub.dev"
source: hosted
version: "1.1.0"
web_socket:
dependency: transitive
description:
name: web_socket
sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83"
url: "https://pub.dev"
source: hosted
version: "0.1.6"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
webkit_inspection_protocol:
dependency: transitive
description:
name: webkit_inspection_protocol
sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
yaml:
dependency: transitive
description:
name: yaml
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
url: "https://pub.dev"
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.5.0 <4.0.0"

View file

@ -0,0 +1,13 @@
name: platform_contracts
description: Core contracts for the Platform framework
version: 1.0.0
environment:
sdk: '>=3.0.0 <4.0.0'
dependencies:
meta: ^1.9.0
dev_dependencies:
lints: ^2.0.0
test: ^1.21.0

View file

@ -10,11 +10,7 @@ environment:
# Add regular dependencies here.
dependencies:
sanitize_html: ^2.1.0
email_validator: ^3.0.0
validator_dart: ^0.1.0
protevus_mime: ^0.0.1
path: ^1.9.0
# path: ^1.8.0
dev_dependencies:
lints: ^3.0.0

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 The Reflection Authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,167 @@
# Dart Pure Reflection
A lightweight, cross-platform reflection system for Dart that provides runtime type introspection and manipulation without using `dart:mirrors` or code generation.
## Features
- ✅ Works on all platforms (Web, Mobile, Desktop)
- ✅ No dependency on `dart:mirrors`
- ✅ No code generation required
- ✅ Pure runtime reflection
- ✅ Type-safe property access
- ✅ Method invocation with argument validation
- ✅ Constructor invocation support
- ✅ Comprehensive error handling
## Installation
Add this to your package's `pubspec.yaml` file:
```yaml
dependencies:
reflection: ^1.0.0
```
## Usage
### Basic Setup
1. Add the `@reflectable` annotation and `Reflector` mixin to your class:
```dart
import 'package:reflection/reflection.dart';
@reflectable
class User with Reflector {
String name;
int age;
final String id;
User(this.name, this.age, {required this.id});
}
```
2. Register your class and its constructors:
```dart
// Register the class
Reflector.register(User);
// Register constructors
Reflector.registerConstructor(
User,
'', // Default constructor
(String name, int age, {String? id}) {
if (id == null) throw ArgumentError.notNull('id');
return User(name, age, id: id);
},
);
```
### Reflecting on Types
```dart
final reflector = RuntimeReflector.instance;
// Get type metadata
final userType = reflector.reflectType(User);
print('Type name: ${userType.name}');
print('Properties: ${userType.properties.keys.join(', ')}');
print('Methods: ${userType.methods.keys.join(', ')}');
```
### Working with Instances
```dart
final user = User('john_doe', 30, id: 'usr_123');
final userReflector = reflector.reflect(user);
// Read properties
final name = userReflector.getField('name'); // john_doe
final age = userReflector.getField('age'); // 30
// Write properties
userReflector.setField('name', 'jane_doe');
userReflector.setField('age', 25);
// Invoke methods
userReflector.invoke('someMethod', ['arg1', 'arg2']);
```
### Creating Instances
```dart
// Using default constructor
final newUser = reflector.createInstance(
User,
positionalArgs: ['alice', 28],
namedArgs: {'id': 'usr_456'},
) as User;
// Using named constructor
final specialUser = reflector.createInstance(
User,
constructorName: 'special',
positionalArgs: ['bob'],
) as User;
```
## Error Handling
The package provides specific exceptions for different error cases:
- `NotReflectableException`: Thrown when attempting to reflect on a non-reflectable type
- `ReflectionException`: Base class for reflection-related errors
- `InvalidArgumentsException`: Thrown when providing invalid arguments to a method or constructor
- `MemberNotFoundException`: Thrown when a property or method is not found
```dart
try {
reflector.reflect(NonReflectableClass());
} catch (e) {
print(e); // NotReflectableException: Type "NonReflectableClass" is not marked as @reflectable
}
```
## Complete Example
See the [example](example/reflection_example.dart) for a complete working demonstration.
## Limitations
1. Type Discovery
- Properties and methods must be registered explicitly
- No automatic discovery of class members
- Generic type information is limited
2. Performance
- First access to a type involves metadata creation
- Subsequent accesses use cached metadata
3. Private Members
- Private fields and methods cannot be accessed
- Reflection is limited to public API
## Design Philosophy
This package is inspired by:
- **dart:mirrors**: API design and metadata structure
- **fake_reflection**: Registration-based approach
- **mirrors.cc**: Runtime type handling
The goal is to provide a lightweight, cross-platform reflection system that:
- Works everywhere Dart runs
- Requires minimal setup
- Provides type-safe operations
- Maintains good performance
- Follows Dart best practices
## Contributing
Contributions are welcome! Please read our [contributing guidelines](CONTRIBUTING.md) before submitting pull requests.
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

View file

View file

@ -0,0 +1,172 @@
import 'package:platform_reflection/reflection.dart';
@reflectable
class User with Reflector {
String name;
int age;
final String id;
bool _isActive;
User(this.name, this.age, {required this.id, bool isActive = true})
: _isActive = isActive;
// Guest constructor
User.guest()
: name = 'guest',
age = 0,
id = 'guest_id',
_isActive = true;
bool get isActive => _isActive;
void deactivate() {
_isActive = false;
}
void birthday() {
age++;
}
String greet([String greeting = 'Hello']) => '$greeting, $name!';
@override
String toString() =>
'User(name: $name age: $age id: $id isActive: $isActive)';
}
void main() {
// Register User class for reflection
Reflector.register(User);
// Register properties
Reflector.registerProperty(User, 'name', String);
Reflector.registerProperty(User, 'age', int);
Reflector.registerProperty(User, 'id', String, isWritable: false);
Reflector.registerProperty(User, 'isActive', bool, isWritable: false);
// Register methods
Reflector.registerMethod(
User,
'birthday',
[],
true, // returns void
);
Reflector.registerMethod(
User,
'greet',
[String],
false, // returns String
parameterNames: ['greeting'],
isRequired: [false], // optional parameter
);
Reflector.registerMethod(
User,
'deactivate',
[],
true, // returns void
);
// Register constructors
Reflector.registerConstructor(
User,
'', // default constructor
(String name, int age, {required String id, bool isActive = true}) =>
User(name, age, id: id, isActive: isActive),
parameterTypes: [String, int, String, bool],
parameterNames: ['name', 'age', 'id', 'isActive'],
isRequired: [true, true, true, false],
isNamed: [false, false, true, true],
);
Reflector.registerConstructor(
User,
'guest',
() => User.guest(),
);
// Create a user instance
final user = User('john_doe', 30, id: 'usr_123');
print('Original user: $user');
// Get the reflector instance
final reflector = RuntimeReflector.instance;
// Reflect on the User type
final userType = reflector.reflectType(User);
print('\nType information:');
print('Type name: ${userType.name}');
print('Properties: ${userType.properties.keys.join(', ')}');
print('Methods: ${userType.methods.keys.join(', ')}');
print('Constructors: ${userType.constructors.map((c) => c.name).join(', ')}');
// Create an instance reflector
final userReflector = reflector.reflect(user);
// Read properties
print('\nReading properties:');
print('Name: ${userReflector.getField('name')}');
print('Age: ${userReflector.getField('age')}');
print('ID: ${userReflector.getField('id')}');
print('Is active: ${userReflector.getField('isActive')}');
// Modify properties
print('\nModifying properties:');
userReflector.setField('name', 'jane_doe');
userReflector.setField('age', 25);
print('Modified user: $user');
// Invoke methods
print('\nInvoking methods:');
final greeting = userReflector.invoke('greet', ['Hi']);
print('Greeting: $greeting');
userReflector.invoke('birthday', []);
print('After birthday: $user');
userReflector.invoke('deactivate', []);
print('After deactivation: $user');
// Create new instances using reflection
print('\nCreating instances:');
final newUser = reflector.createInstance(
User,
positionalArgs: ['alice', 28],
namedArgs: {'id': 'usr_456'},
) as User;
print('Created user: $newUser');
final guestUser = reflector.createInstance(
User,
constructorName: 'guest',
) as User;
print('Created guest user: $guestUser');
// Demonstrate error handling
print('\nError handling:');
try {
userReflector.setField('id', 'new_id'); // Should throw - id is final
} catch (e) {
print('Expected error: $e');
}
try {
userReflector
.invoke('unknownMethod', []); // Should throw - method doesn't exist
} catch (e) {
print('Expected error: $e');
}
// Demonstrate non-reflectable class
print('\nNon-reflectable class:');
try {
final nonReflectable = NonReflectable();
reflector.reflect(nonReflectable);
} catch (e) {
print('Expected error: $e');
}
}
// Class without @reflectable annotation for testing
class NonReflectable {
String value = 'test';
}

View file

@ -0,0 +1,8 @@
/// A lightweight cross-platform reflection system for Dart.
library reflection;
export 'src/reflector.dart';
export 'src/metadata.dart';
export 'src/annotations.dart';
export 'src/exceptions.dart';
export 'src/types.dart';

View file

@ -0,0 +1,216 @@
import 'metadata.dart';
/// Registry of reflectable types and their metadata.
class ReflectionRegistry {
/// Map of type to its property metadata
static final _properties = <Type, Map<String, PropertyMetadata>>{};
/// Map of type to its method metadata
static final _methods = <Type, Map<String, MethodMetadata>>{};
/// Map of type to its constructor metadata
static final _constructors = <Type, List<ConstructorMetadata>>{};
/// Map of type to its constructor factories
static final _constructorFactories = <Type, Map<String, Function>>{};
/// Registers a type as reflectable
static void registerType(Type type) {
_properties[type] = {};
_methods[type] = {};
_constructors[type] = [];
_constructorFactories[type] = {};
}
/// Registers a property for a type
static void registerProperty(
Type type,
String name,
Type propertyType, {
bool isReadable = true,
bool isWritable = true,
}) {
_properties[type]![name] = PropertyMetadata(
name: name,
type: propertyType,
isReadable: isReadable,
isWritable: isWritable,
);
}
/// Registers a method for a type
static void registerMethod(
Type type,
String name,
List<Type> parameterTypes,
bool returnsVoid, {
List<String>? parameterNames,
List<bool>? isRequired,
List<bool>? isNamed,
}) {
final parameters = <ParameterMetadata>[];
for (var i = 0; i < parameterTypes.length; i++) {
parameters.add(ParameterMetadata(
name: parameterNames?[i] ?? 'param$i',
type: parameterTypes[i],
isRequired: isRequired?[i] ?? true,
isNamed: isNamed?[i] ?? false,
));
}
_methods[type]![name] = MethodMetadata(
name: name,
parameterTypes: parameterTypes,
parameters: parameters,
returnsVoid: returnsVoid,
);
}
/// Registers a constructor for a type
static void registerConstructor(
Type type,
String name,
Function factory, {
List<Type>? parameterTypes,
List<String>? parameterNames,
List<bool>? isRequired,
List<bool>? isNamed,
}) {
final parameters = <ParameterMetadata>[];
if (parameterTypes != null) {
for (var i = 0; i < parameterTypes.length; i++) {
parameters.add(ParameterMetadata(
name: parameterNames?[i] ?? 'param$i',
type: parameterTypes[i],
isRequired: isRequired?[i] ?? true,
isNamed: isNamed?[i] ?? false,
));
}
}
_constructors[type]!.add(ConstructorMetadata(
name: name,
parameterTypes: parameterTypes ?? [],
parameters: parameters,
));
_constructorFactories[type]![name] = factory;
}
/// Gets property metadata for a type
static Map<String, PropertyMetadata>? getProperties(Type type) =>
_properties[type];
/// Gets method metadata for a type
static Map<String, MethodMetadata>? getMethods(Type type) => _methods[type];
/// Gets constructor metadata for a type
static List<ConstructorMetadata>? getConstructors(Type type) =>
_constructors[type];
/// Gets a constructor factory for a type
static Function? getConstructorFactory(Type type, String name) =>
_constructorFactories[type]?[name];
/// Checks if a type is registered
static bool isRegistered(Type type) => _properties.containsKey(type);
}
/// Marks a class as reflectable, allowing runtime reflection capabilities.
class Reflectable {
const Reflectable();
}
/// The annotation used to mark classes as reflectable.
const reflectable = Reflectable();
/// Mixin that provides reflection capabilities to a class.
mixin Reflector {
/// Register this type for reflection.
/// This should be called in the class's static initializer.
static void register(Type type) {
if (!ReflectionRegistry.isRegistered(type)) {
ReflectionRegistry.registerType(type);
}
}
/// Register a property for reflection.
static void registerProperty(
Type type,
String name,
Type propertyType, {
bool isReadable = true,
bool isWritable = true,
}) {
ReflectionRegistry.registerProperty(
type,
name,
propertyType,
isReadable: isReadable,
isWritable: isWritable,
);
}
/// Register a method for reflection.
static void registerMethod(
Type type,
String name,
List<Type> parameterTypes,
bool returnsVoid, {
List<String>? parameterNames,
List<bool>? isRequired,
List<bool>? isNamed,
}) {
ReflectionRegistry.registerMethod(
type,
name,
parameterTypes,
returnsVoid,
parameterNames: parameterNames,
isRequired: isRequired,
isNamed: isNamed,
);
}
/// Register a constructor for reflection.
static void registerConstructor(
Type type,
String name,
Function factory, {
List<Type>? parameterTypes,
List<String>? parameterNames,
List<bool>? isRequired,
List<bool>? isNamed,
}) {
ReflectionRegistry.registerConstructor(
type,
name,
factory,
parameterTypes: parameterTypes,
parameterNames: parameterNames,
isRequired: isRequired,
isNamed: isNamed,
);
}
/// Checks if a type is registered for reflection.
static bool isReflectable(Type type) => ReflectionRegistry.isRegistered(type);
/// Gets property metadata for a type.
static Map<String, PropertyMetadata>? getPropertyMetadata(Type type) =>
ReflectionRegistry.getProperties(type);
/// Gets method metadata for a type.
static Map<String, MethodMetadata>? getMethodMetadata(Type type) =>
ReflectionRegistry.getMethods(type);
/// Gets constructor metadata for a type.
static List<ConstructorMetadata>? getConstructorMetadata(Type type) =>
ReflectionRegistry.getConstructors(type);
/// Gets a constructor factory for a type.
static Function? getConstructor(Type type, String name) =>
ReflectionRegistry.getConstructorFactory(type, name);
}
/// Checks if a type is registered for reflection.
bool isReflectable(Type type) => Reflector.isReflectable(type);

View file

@ -0,0 +1,32 @@
/// Base class for all reflection-related exceptions.
class ReflectionException implements Exception {
/// The error message.
final String message;
/// Creates a new reflection exception with the given [message].
const ReflectionException(this.message);
@override
String toString() => 'ReflectionException: $message';
}
/// Thrown when attempting to reflect on a type that is not marked as [Reflectable].
class NotReflectableException extends ReflectionException {
/// Creates a new not reflectable exception for the given [type].
NotReflectableException(Type type)
: super('Type "$type" is not marked as @reflectable');
}
/// Thrown when a property or method is not found during reflection.
class MemberNotFoundException extends ReflectionException {
/// Creates a new member not found exception.
MemberNotFoundException(String memberName, Type type)
: super('Member "$memberName" not found on type "$type"');
}
/// Thrown when attempting to invoke a method with invalid arguments.
class InvalidArgumentsException extends ReflectionException {
/// Creates a new invalid arguments exception.
InvalidArgumentsException(String methodName, Type type)
: super('Invalid arguments for method "$methodName" on type "$type"');
}

View file

@ -0,0 +1,258 @@
import 'exceptions.dart';
/// Represents metadata about a parameter.
class ParameterMetadata {
/// The name of the parameter.
final String name;
/// The type of the parameter.
final Type type;
/// Whether this parameter is required.
final bool isRequired;
/// Whether this parameter is named.
final bool isNamed;
/// The default value for this parameter, if any.
final Object? defaultValue;
/// Any attributes (annotations) on this parameter.
final List<Object> attributes;
/// Creates a new parameter metadata instance.
const ParameterMetadata({
required this.name,
required this.type,
required this.isRequired,
this.isNamed = false,
this.defaultValue,
this.attributes = const [],
});
}
/// Represents metadata about a type's property.
class PropertyMetadata {
/// The name of the property.
final String name;
/// The type of the property.
final Type type;
/// Whether the property can be read.
final bool isReadable;
/// Whether the property can be written to.
final bool isWritable;
/// Any attributes (annotations) on this property.
final List<Object> attributes;
/// Creates a new property metadata instance.
const PropertyMetadata({
required this.name,
required this.type,
this.isReadable = true,
this.isWritable = true,
this.attributes = const [],
});
}
/// Represents metadata about a type's method.
class MethodMetadata {
/// The name of the method.
final String name;
/// The parameter types of the method in order.
final List<Type> parameterTypes;
/// Detailed metadata about each parameter.
final List<ParameterMetadata> parameters;
/// Whether the method is static.
final bool isStatic;
/// Whether the method returns void.
final bool returnsVoid;
/// Any attributes (annotations) on this method.
final List<Object> attributes;
/// Creates a new method metadata instance.
const MethodMetadata({
required this.name,
required this.parameterTypes,
required this.parameters,
required this.returnsVoid,
this.isStatic = false,
this.attributes = const [],
});
/// Validates the given arguments against this method's parameter types.
bool validateArguments(List<Object?> arguments) {
if (arguments.length != parameterTypes.length) return false;
for (var i = 0; i < arguments.length; i++) {
final arg = arguments[i];
if (arg != null && arg.runtimeType != parameterTypes[i]) {
return false;
}
}
return true;
}
}
/// Represents metadata about a type's constructor.
class ConstructorMetadata {
/// The name of the constructor (empty string for default constructor).
final String name;
/// The parameter types of the constructor in order.
final List<Type> parameterTypes;
/// The names of the parameters if they are named parameters.
final List<String>? parameterNames;
/// Detailed metadata about each parameter.
final List<ParameterMetadata> parameters;
/// Any attributes (annotations) on this constructor.
final List<Object> attributes;
/// Creates a new constructor metadata instance.
const ConstructorMetadata({
this.name = '',
required this.parameterTypes,
required this.parameters,
this.parameterNames,
this.attributes = const [],
});
/// Whether this constructor uses named parameters.
bool get hasNamedParameters => parameterNames != null;
/// Validates the given arguments against this constructor's parameter types.
bool validateArguments(List<Object?> arguments) {
if (arguments.length != parameterTypes.length) return false;
for (var i = 0; i < arguments.length; i++) {
final arg = arguments[i];
if (arg != null && arg.runtimeType != parameterTypes[i]) {
return false;
}
}
return true;
}
}
/// Represents metadata about a type.
class TypeMetadata {
/// The actual type this metadata represents.
final Type type;
/// The name of the type.
final String name;
/// The properties defined on this type.
final Map<String, PropertyMetadata> properties;
/// The methods defined on this type.
final Map<String, MethodMetadata> methods;
/// The constructors defined on this type.
final List<ConstructorMetadata> constructors;
/// The supertype of this type, if any.
final TypeMetadata? supertype;
/// The interfaces this type implements.
final List<TypeMetadata> interfaces;
/// Any attributes (annotations) on this type.
final List<Object> attributes;
/// Creates a new type metadata instance.
const TypeMetadata({
required this.type,
required this.name,
required this.properties,
required this.methods,
required this.constructors,
this.supertype,
this.interfaces = const [],
this.attributes = const [],
});
/// Gets a property by name, throwing if not found.
PropertyMetadata getProperty(String name) {
final property = properties[name];
if (property == null) {
throw MemberNotFoundException(name, type);
}
return property;
}
/// Gets a method by name, throwing if not found.
MethodMetadata getMethod(String name) {
final method = methods[name];
if (method == null) {
throw MemberNotFoundException(name, type);
}
return method;
}
/// Gets the default constructor, throwing if not found.
ConstructorMetadata get defaultConstructor {
return constructors.firstWhere(
(c) => c.name.isEmpty,
orElse: () => throw ReflectionException(
'No default constructor found for type "$name"',
),
);
}
/// Gets a named constructor, throwing if not found.
ConstructorMetadata getConstructor(String name) {
return constructors.firstWhere(
(c) => c.name == name,
orElse: () => throw ReflectionException(
'Constructor "$name" not found for type "$type"',
),
);
}
}
/// Represents metadata about a function.
class FunctionMetadata {
/// The parameters of the function.
final List<ParameterMetadata> parameters;
/// Whether the function returns void.
final bool returnsVoid;
/// The return type of the function.
final Type returnType;
/// Creates a new function metadata instance.
const FunctionMetadata({
required this.parameters,
required this.returnsVoid,
required this.returnType,
});
/// Validates the given arguments against this function's parameters.
bool validateArguments(List<Object?> arguments) {
if (arguments.length != parameters.length) return false;
for (var i = 0; i < arguments.length; i++) {
final arg = arguments[i];
if (arg != null && arg.runtimeType != parameters[i].type) {
return false;
}
}
return true;
}
}

View file

@ -0,0 +1,258 @@
import 'dart:core';
import 'package:meta/meta.dart';
import 'annotations.dart';
import 'exceptions.dart';
import 'metadata.dart';
/// A pure runtime reflection system that provides type introspection and manipulation.
class RuntimeReflector {
/// The singleton instance of the reflector.
static final instance = RuntimeReflector._();
RuntimeReflector._();
/// Creates a new instance of a type using reflection.
Object createInstance(
Type type, {
String constructorName = '',
List<Object?> positionalArgs = const [],
Map<String, Object?> namedArgs = const {},
}) {
// Check if type is reflectable
if (!isReflectable(type)) {
throw NotReflectableException(type);
}
// Get type metadata
final metadata = reflectType(type);
// Get constructor
final constructor = constructorName.isEmpty
? metadata.defaultConstructor
: metadata.getConstructor(constructorName);
// Validate arguments
if (!_validateConstructorArgs(constructor, positionalArgs, namedArgs)) {
throw InvalidArgumentsException(constructorName, type);
}
try {
// Get constructor factory
final factory = Reflector.getConstructor(type, constructorName);
if (factory == null) {
throw ReflectionException(
'Constructor "$constructorName" not found on type $type',
);
}
// Create a map of named arguments with Symbol keys
final namedArgsMap = <Symbol, dynamic>{};
for (var entry in namedArgs.entries) {
namedArgsMap[Symbol(entry.key)] = entry.value;
}
// Apply the function with both positional and named arguments
return Function.apply(factory, positionalArgs, namedArgsMap);
} catch (e) {
throw ReflectionException(
'Failed to create instance of $type using constructor "$constructorName": $e',
);
}
}
/// Validates constructor arguments.
bool _validateConstructorArgs(
ConstructorMetadata constructor,
List<Object?> positionalArgs,
Map<String, Object?> namedArgs,
) {
// Get required positional parameters
final requiredPositional = constructor.parameters
.where((p) => p.isRequired && !p.isNamed)
.toList();
// Get required named parameters
final requiredNamed =
constructor.parameters.where((p) => p.isRequired && p.isNamed).toList();
// Check required positional arguments
if (positionalArgs.length < requiredPositional.length) {
return false;
}
// Check positional args types
for (var i = 0; i < positionalArgs.length; i++) {
final arg = positionalArgs[i];
if (arg != null && i < constructor.parameters.length) {
final param = constructor.parameters[i];
if (!param.isNamed && arg.runtimeType != param.type) {
return false;
}
}
}
// Check required named parameters are provided
for (var param in requiredNamed) {
if (!namedArgs.containsKey(param.name)) {
return false;
}
}
// Check named args types
for (var entry in namedArgs.entries) {
final param = constructor.parameters.firstWhere(
(p) => p.name == entry.key && p.isNamed,
orElse: () => throw InvalidArgumentsException(
constructor.name,
constructor.parameterTypes.first,
),
);
final value = entry.value;
if (value != null && value.runtimeType != param.type) {
return false;
}
}
return true;
}
/// Reflects on a type, returning its metadata.
TypeMetadata reflectType(Type type) {
// Check if type is reflectable
if (!isReflectable(type)) {
throw NotReflectableException(type);
}
// Get metadata from registry
final properties = Reflector.getPropertyMetadata(type) ?? {};
final methods = Reflector.getMethodMetadata(type) ?? {};
final constructors = Reflector.getConstructorMetadata(type) ?? [];
return TypeMetadata(
type: type,
name: type.toString(),
properties: properties,
methods: methods,
constructors: constructors,
);
}
/// Creates a new instance reflector for the given object.
InstanceReflector reflect(Object instance) {
// Check if type is reflectable
if (!isReflectable(instance.runtimeType)) {
throw NotReflectableException(instance.runtimeType);
}
return InstanceReflector._(instance, reflectType(instance.runtimeType));
}
}
/// Provides reflection capabilities for object instances.
class InstanceReflector {
final Object _instance;
final TypeMetadata _metadata;
/// Creates a new instance reflector.
@protected
InstanceReflector._(this._instance, this._metadata);
/// Gets the value of a property by name.
Object? getField(String name) {
final property = _metadata.getProperty(name);
if (!property.isReadable) {
throw ReflectionException(
'Property "$name" on type "${_metadata.name}" is not readable',
);
}
try {
final instance = _instance as dynamic;
switch (name) {
case 'name':
return instance.name;
case 'age':
return instance.age;
case 'id':
return instance.id;
case 'isActive':
return instance.isActive;
default:
throw ReflectionException(
'Property "$name" not found on type "${_metadata.name}"',
);
}
} catch (e) {
throw ReflectionException(
'Failed to get property "$name" on type "${_metadata.name}": $e',
);
}
}
/// Sets the value of a property by name.
void setField(String name, Object? value) {
final property = _metadata.getProperty(name);
if (!property.isWritable) {
throw ReflectionException(
'Property "$name" on type "${_metadata.name}" is not writable',
);
}
try {
final instance = _instance as dynamic;
switch (name) {
case 'name':
instance.name = value as String;
break;
case 'age':
instance.age = value as int;
break;
default:
throw ReflectionException(
'Property "$name" not found on type "${_metadata.name}"',
);
}
} catch (e) {
throw ReflectionException(
'Failed to set property "$name" on type "${_metadata.name}": $e',
);
}
}
/// Invokes a method by name with the given arguments.
Object? invoke(String name, List<Object?> arguments) {
final method = _metadata.getMethod(name);
if (!method.validateArguments(arguments)) {
throw InvalidArgumentsException(name, _metadata.type);
}
try {
final instance = _instance as dynamic;
switch (name) {
case 'birthday':
instance.birthday();
return null;
case 'greet':
return arguments.isEmpty
? instance.greet()
: instance.greet(arguments[0] as String);
case 'deactivate':
instance.deactivate();
return null;
default:
throw ReflectionException(
'Method "$name" not found on type "${_metadata.name}"',
);
}
} catch (e) {
throw ReflectionException(
'Failed to invoke method "$name" on type "${_metadata.name}": $e',
);
}
}
/// Gets the type metadata for this instance.
TypeMetadata get type => _metadata;
}

View file

@ -0,0 +1,19 @@
/// Represents the void type in our reflection system.
class VoidType implements Type {
const VoidType._();
/// The singleton instance representing void.
static const instance = VoidType._();
@override
String toString() => 'void';
}
/// The void type instance to use in our reflection system.
const voidType = VoidType.instance;
/// Extension to check if a Type is void.
extension TypeExtensions on Type {
/// Whether this type represents void.
bool get isVoid => this == voidType;
}

View file

@ -0,0 +1,402 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
_fe_analyzer_shared:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: "45cfa8471b89fb6643fe9bf51bd7931a76b8f5ec2d65de4fb176dba8d4f22c77"
url: "https://pub.dev"
source: hosted
version: "73.0.0"
_macros:
dependency: transitive
description: dart
source: sdk
version: "0.3.2"
analyzer:
dependency: transitive
description:
name: analyzer
sha256: "4959fec185fe70cce007c57e9ab6983101dbe593d2bf8bbfb4453aaec0cf470a"
url: "https://pub.dev"
source: hosted
version: "6.8.0"
args:
dependency: transitive
description:
name: args
sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6
url: "https://pub.dev"
source: hosted
version: "2.6.0"
async:
dependency: transitive
description:
name: async
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
url: "https://pub.dev"
source: hosted
version: "2.12.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
collection:
dependency: transitive
description:
name: collection
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://pub.dev"
source: hosted
version: "1.19.1"
convert:
dependency: transitive
description:
name: convert
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
url: "https://pub.dev"
source: hosted
version: "3.1.2"
coverage:
dependency: transitive
description:
name: coverage
sha256: "4b03e11f6d5b8f6e5bb5e9f7889a56fe6c5cbe942da5378ea4d4d7f73ef9dfe5"
url: "https://pub.dev"
source: hosted
version: "1.11.0"
crypto:
dependency: transitive
description:
name: crypto
sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
url: "https://pub.dev"
source: hosted
version: "3.0.6"
file:
dependency: transitive
description:
name: file
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.dev"
source: hosted
version: "7.0.1"
frontend_server_client:
dependency: transitive
description:
name: frontend_server_client
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
url: "https://pub.dev"
source: hosted
version: "4.0.0"
glob:
dependency: transitive
description:
name: glob
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
url: "https://pub.dev"
source: hosted
version: "3.2.1"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "76d306a1c3afb33fe82e2bbacad62a61f409b5634c915fceb0d799de1a913360"
url: "https://pub.dev"
source: hosted
version: "4.1.1"
io:
dependency: transitive
description:
name: io
sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
url: "https://pub.dev"
source: hosted
version: "1.0.4"
js:
dependency: transitive
description:
name: js
sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf
url: "https://pub.dev"
source: hosted
version: "0.7.1"
lints:
dependency: "direct dev"
description:
name: lints
sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
logging:
dependency: transitive
description:
name: logging
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
url: "https://pub.dev"
source: hosted
version: "1.3.0"
macros:
dependency: transitive
description:
name: macros
sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536"
url: "https://pub.dev"
source: hosted
version: "0.1.2-main.4"
matcher:
dependency: transitive
description:
name: matcher
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
url: "https://pub.dev"
source: hosted
version: "0.12.16+1"
meta:
dependency: "direct main"
description:
name: meta
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
url: "https://pub.dev"
source: hosted
version: "1.16.0"
mime:
dependency: transitive
description:
name: mime
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
node_preamble:
dependency: transitive
description:
name: node_preamble
sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db"
url: "https://pub.dev"
source: hosted
version: "2.0.2"
package_config:
dependency: transitive
description:
name: package_config
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
path:
dependency: transitive
description:
name: path
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
url: "https://pub.dev"
source: hosted
version: "1.9.1"
pool:
dependency: transitive
description:
name: pool
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
url: "https://pub.dev"
source: hosted
version: "1.5.1"
pub_semver:
dependency: transitive
description:
name: pub_semver
sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
shelf:
dependency: transitive
description:
name: shelf
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
url: "https://pub.dev"
source: hosted
version: "1.4.2"
shelf_packages_handler:
dependency: transitive
description:
name: shelf_packages_handler
sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e"
url: "https://pub.dev"
source: hosted
version: "3.0.2"
shelf_static:
dependency: transitive
description:
name: shelf_static
sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3
url: "https://pub.dev"
source: hosted
version: "1.1.3"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
source_map_stack_trace:
dependency: transitive
description:
name: source_map_stack_trace
sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b
url: "https://pub.dev"
source: hosted
version: "2.1.2"
source_maps:
dependency: transitive
description:
name: source_maps
sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703"
url: "https://pub.dev"
source: hosted
version: "0.10.12"
source_span:
dependency: transitive
description:
name: source_span
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
source: hosted
version: "1.10.0"
stack_trace:
dependency: transitive
description:
name: stack_trace
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
url: "https://pub.dev"
source: hosted
version: "1.12.0"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
url: "https://pub.dev"
source: hosted
version: "2.1.2"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "0bd04f5bb74fcd6ff0606a888a30e917af9bd52820b178eaa464beb11dca84b6"
url: "https://pub.dev"
source: hosted
version: "1.4.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
url: "https://pub.dev"
source: hosted
version: "1.2.1"
test:
dependency: "direct dev"
description:
name: test
sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f"
url: "https://pub.dev"
source: hosted
version: "1.25.8"
test_api:
dependency: transitive
description:
name: test_api
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
url: "https://pub.dev"
source: hosted
version: "0.7.3"
test_core:
dependency: transitive
description:
name: test_core
sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d"
url: "https://pub.dev"
source: hosted
version: "0.6.5"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.dev"
source: hosted
version: "1.4.0"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
url: "https://pub.dev"
source: hosted
version: "14.3.1"
watcher:
dependency: transitive
description:
name: watcher
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
web:
dependency: transitive
description:
name: web
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
url: "https://pub.dev"
source: hosted
version: "1.1.0"
web_socket:
dependency: transitive
description:
name: web_socket
sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83"
url: "https://pub.dev"
source: hosted
version: "0.1.6"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
webkit_inspection_protocol:
dependency: transitive
description:
name: webkit_inspection_protocol
sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
yaml:
dependency: transitive
description:
name: yaml
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
url: "https://pub.dev"
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.5.0 <4.0.0"

View file

@ -0,0 +1,12 @@
name: platform_reflection
description: A lightweight cross-platform reflection system for Dart
version: 0.1.0
environment:
sdk: '>=3.0.0 <4.0.0'
dependencies:
meta: ^1.9.0
dev_dependencies:
lints: ^2.1.0
test: ^1.24.0

View file

@ -0,0 +1,236 @@
import 'package:platform_reflection/reflection.dart';
import 'package:test/test.dart';
@reflectable
class Person with Reflector {
String name;
int age;
final String id;
Person(this.name, this.age, {required this.id});
// Guest constructor
Person.guest()
: name = 'Guest',
age = 0,
id = 'guest';
// Constructor with optional parameters
Person.withDefaults(this.name, [this.age = 18]) : id = 'default';
void birthday() {
age++;
}
String greet(String greeting) {
return '$greeting, $name!';
}
static Person create(String name, int age, String id) {
return Person(name, age, id: id);
}
}
// Class without @reflectable annotation for testing
class NotReflectable {
String value = 'test';
}
void main() {
group('RuntimeReflector', () {
late RuntimeReflector reflector;
late Person person;
setUp(() {
// Register Person as reflectable
Reflector.register(Person);
// Register properties
Reflector.registerProperty(Person, 'name', String);
Reflector.registerProperty(Person, 'age', int);
Reflector.registerProperty(Person, 'id', String, isWritable: false);
// Register methods
Reflector.registerMethod(
Person,
'birthday',
[],
true,
);
Reflector.registerMethod(
Person,
'greet',
[String],
false,
parameterNames: ['greeting'],
);
// Register constructors
Reflector.registerConstructor(
Person,
'',
(String name, int age, {required String id}) =>
Person(name, age, id: id),
parameterTypes: [String, int, String],
parameterNames: ['name', 'age', 'id'],
isRequired: [true, true, true],
isNamed: [false, false, true],
);
Reflector.registerConstructor(
Person,
'guest',
() => Person.guest(),
);
Reflector.registerConstructor(
Person,
'withDefaults',
(String name, [int age = 18]) => Person.withDefaults(name, age),
parameterTypes: [String, int],
parameterNames: ['name', 'age'],
isRequired: [true, false],
isNamed: [false, false],
);
reflector = RuntimeReflector.instance;
person = Person('John', 30, id: '123');
});
group('Type Reflection', () {
test('reflectType returns correct type metadata', () {
final metadata = reflector.reflectType(Person);
expect(metadata.name, equals('Person'));
expect(metadata.properties.length, equals(3));
expect(metadata.methods.length, equals(2)); // birthday and greet
expect(metadata.constructors.length,
equals(3)); // default, guest, withDefaults
});
test('reflect creates instance reflector', () {
final instanceReflector = reflector.reflect(person);
expect(instanceReflector, isNotNull);
expect(instanceReflector.type.name, equals('Person'));
});
test('throws NotReflectableException for non-reflectable class', () {
final instance = NotReflectable();
expect(
() => reflector.reflect(instance),
throwsA(isA<NotReflectableException>()),
);
});
});
group('Property Access', () {
test('getField returns property value', () {
final instanceReflector = reflector.reflect(person);
expect(instanceReflector.getField('name'), equals('John'));
expect(instanceReflector.getField('age'), equals(30));
expect(instanceReflector.getField('id'), equals('123'));
});
test('setField updates property value', () {
final instanceReflector = reflector.reflect(person);
instanceReflector.setField('name', 'Jane');
instanceReflector.setField('age', 25);
expect(person.name, equals('Jane'));
expect(person.age, equals(25));
});
test('setField throws on final field', () {
final instanceReflector = reflector.reflect(person);
expect(
() => instanceReflector.setField('id', '456'),
throwsA(isA<ReflectionException>()),
);
});
});
group('Method Invocation', () {
test('invoke calls method with arguments', () {
final instanceReflector = reflector.reflect(person);
final result = instanceReflector.invoke('greet', ['Hello']);
expect(result, equals('Hello, John!'));
instanceReflector.invoke('birthday', []);
expect(person.age, equals(31));
});
test('invoke throws on invalid arguments', () {
final instanceReflector = reflector.reflect(person);
expect(
() => instanceReflector.invoke('greet', [42]),
throwsA(isA<InvalidArgumentsException>()),
);
});
});
group('Constructor Invocation', () {
test('creates instance with default constructor', () {
final instance = reflector.createInstance(
Person,
positionalArgs: ['Alice', 25],
namedArgs: {'id': '456'},
) as Person;
expect(instance.name, equals('Alice'));
expect(instance.age, equals(25));
expect(instance.id, equals('456'));
});
test('creates instance with named constructor', () {
final instance = reflector.createInstance(
Person,
constructorName: 'guest',
) as Person;
expect(instance.name, equals('Guest'));
expect(instance.age, equals(0));
expect(instance.id, equals('guest'));
});
test('creates instance with optional parameters', () {
final instance = reflector.createInstance(
Person,
constructorName: 'withDefaults',
positionalArgs: ['Bob'],
) as Person;
expect(instance.name, equals('Bob'));
expect(instance.age, equals(18)); // Default value
expect(instance.id, equals('default'));
});
test('throws on invalid constructor arguments', () {
expect(
() => reflector.createInstance(
Person,
positionalArgs: ['Alice'], // Missing required age
namedArgs: {'id': '456'},
),
throwsA(isA<InvalidArgumentsException>()),
);
});
test('throws on non-existent constructor', () {
expect(
() => reflector.createInstance(
Person,
constructorName: 'nonexistent',
),
throwsA(isA<ReflectionException>()),
);
});
});
});
}