Compare commits
3 commits
6ff734bdf7
...
b5a0c61dd3
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b5a0c61dd3 | ||
![]() |
626c550e27 | ||
![]() |
1373460cac |
42 changed files with 4979 additions and 5 deletions
71
packages/contracts/lib/contracts.dart
Normal file
71
packages/contracts/lib/contracts.dart
Normal 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
|
2
packages/contracts/lib/src/bus/bus.dart
Normal file
2
packages/contracts/lib/src/bus/bus.dart
Normal file
|
@ -0,0 +1,2 @@
|
|||
/// Bus package contracts
|
||||
export 'bus_contract.dart';
|
196
packages/contracts/lib/src/bus/bus_contract.dart
Normal file
196
packages/contracts/lib/src/bus/bus_contract.dart
Normal 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();
|
||||
}
|
3
packages/contracts/lib/src/container/container.dart
Normal file
3
packages/contracts/lib/src/container/container.dart
Normal file
|
@ -0,0 +1,3 @@
|
|||
/// Container package contracts
|
||||
export 'container_contract.dart';
|
||||
export 'contextual_binding_contract.dart';
|
154
packages/contracts/lib/src/container/container_contract.dart
Normal file
154
packages/contracts/lib/src/container/container_contract.dart
Normal 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);
|
||||
}
|
|
@ -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);
|
||||
}
|
193
packages/contracts/lib/src/events/event_dispatcher_contract.dart
Normal file
193
packages/contracts/lib/src/events/event_dispatcher_contract.dart
Normal 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;
|
||||
}
|
2
packages/contracts/lib/src/events/events.dart
Normal file
2
packages/contracts/lib/src/events/events.dart
Normal file
|
@ -0,0 +1,2 @@
|
|||
/// Events package contracts
|
||||
export 'event_dispatcher_contract.dart';
|
2
packages/contracts/lib/src/http/http.dart
Normal file
2
packages/contracts/lib/src/http/http.dart
Normal file
|
@ -0,0 +1,2 @@
|
|||
/// HTTP package contracts
|
||||
export 'http_contract.dart';
|
299
packages/contracts/lib/src/http/http_contract.dart
Normal file
299
packages/contracts/lib/src/http/http_contract.dart
Normal 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);
|
||||
}
|
2
packages/contracts/lib/src/model/model.dart
Normal file
2
packages/contracts/lib/src/model/model.dart
Normal file
|
@ -0,0 +1,2 @@
|
|||
/// Model package contracts
|
||||
export 'model_contract.dart';
|
148
packages/contracts/lib/src/model/model_contract.dart
Normal file
148
packages/contracts/lib/src/model/model_contract.dart
Normal 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;
|
||||
}
|
2
packages/contracts/lib/src/pipeline/pipeline.dart
Normal file
2
packages/contracts/lib/src/pipeline/pipeline.dart
Normal file
|
@ -0,0 +1,2 @@
|
|||
/// Pipeline package contracts
|
||||
export 'pipeline_contract.dart';
|
127
packages/contracts/lib/src/pipeline/pipeline_contract.dart
Normal file
127
packages/contracts/lib/src/pipeline/pipeline_contract.dart
Normal 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);
|
||||
}
|
2
packages/contracts/lib/src/process/process.dart
Normal file
2
packages/contracts/lib/src/process/process.dart
Normal file
|
@ -0,0 +1,2 @@
|
|||
/// Process package contracts
|
||||
export 'process_contract.dart';
|
251
packages/contracts/lib/src/process/process_contract.dart
Normal file
251
packages/contracts/lib/src/process/process_contract.dart
Normal 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();
|
||||
}
|
2
packages/contracts/lib/src/queue/queue.dart
Normal file
2
packages/contracts/lib/src/queue/queue.dart
Normal file
|
@ -0,0 +1,2 @@
|
|||
/// Queue package contracts
|
||||
export 'queue_contract.dart';
|
284
packages/contracts/lib/src/queue/queue_contract.dart
Normal file
284
packages/contracts/lib/src/queue/queue_contract.dart
Normal 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);
|
||||
}
|
2
packages/contracts/lib/src/reflection/reflection.dart
Normal file
2
packages/contracts/lib/src/reflection/reflection.dart
Normal file
|
@ -0,0 +1,2 @@
|
|||
/// Reflection package contracts
|
||||
export 'reflector_contract.dart';
|
147
packages/contracts/lib/src/reflection/reflector_contract.dart
Normal file
147
packages/contracts/lib/src/reflection/reflector_contract.dart
Normal 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);
|
||||
}
|
2
packages/contracts/lib/src/routing/routing.dart
Normal file
2
packages/contracts/lib/src/routing/routing.dart
Normal file
|
@ -0,0 +1,2 @@
|
|||
/// Routing package contracts
|
||||
export 'routing_contract.dart';
|
260
packages/contracts/lib/src/routing/routing_contract.dart
Normal file
260
packages/contracts/lib/src/routing/routing_contract.dart
Normal 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});
|
||||
}
|
2
packages/contracts/lib/src/support/support.dart
Normal file
2
packages/contracts/lib/src/support/support.dart
Normal file
|
@ -0,0 +1,2 @@
|
|||
/// Support package contracts
|
||||
export 'support_contract.dart';
|
263
packages/contracts/lib/src/support/support_contract.dart
Normal file
263
packages/contracts/lib/src/support/support_contract.dart
Normal 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 = {};
|
||||
}
|
2
packages/contracts/lib/src/testing/testing.dart
Normal file
2
packages/contracts/lib/src/testing/testing.dart
Normal file
|
@ -0,0 +1,2 @@
|
|||
/// Testing package contracts
|
||||
export 'testing_contract.dart';
|
302
packages/contracts/lib/src/testing/testing_contract.dart
Normal file
302
packages/contracts/lib/src/testing/testing_contract.dart
Normal 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;
|
||||
}
|
402
packages/contracts/pubspec.lock
Normal file
402
packages/contracts/pubspec.lock
Normal 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"
|
13
packages/contracts/pubspec.yaml
Normal file
13
packages/contracts/pubspec.yaml
Normal 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
|
|
@ -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
|
||||
|
|
21
packages/reflection/LICENSE
Normal file
21
packages/reflection/LICENSE
Normal 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.
|
167
packages/reflection/README.md
Normal file
167
packages/reflection/README.md
Normal 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.
|
0
packages/reflection/doc/.gitkeep
Normal file
0
packages/reflection/doc/.gitkeep
Normal file
172
packages/reflection/example/reflection_example.dart
Normal file
172
packages/reflection/example/reflection_example.dart
Normal 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';
|
||||
}
|
8
packages/reflection/lib/reflection.dart
Normal file
8
packages/reflection/lib/reflection.dart
Normal 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';
|
216
packages/reflection/lib/src/annotations.dart
Normal file
216
packages/reflection/lib/src/annotations.dart
Normal 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);
|
32
packages/reflection/lib/src/exceptions.dart
Normal file
32
packages/reflection/lib/src/exceptions.dart
Normal 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"');
|
||||
}
|
258
packages/reflection/lib/src/metadata.dart
Normal file
258
packages/reflection/lib/src/metadata.dart
Normal 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;
|
||||
}
|
||||
}
|
258
packages/reflection/lib/src/reflector.dart
Normal file
258
packages/reflection/lib/src/reflector.dart
Normal 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;
|
||||
}
|
19
packages/reflection/lib/src/types.dart
Normal file
19
packages/reflection/lib/src/types.dart
Normal 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;
|
||||
}
|
402
packages/reflection/pubspec.lock
Normal file
402
packages/reflection/pubspec.lock
Normal 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"
|
12
packages/reflection/pubspec.yaml
Normal file
12
packages/reflection/pubspec.yaml
Normal 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
|
236
packages/reflection/test/reflection_test.dart
Normal file
236
packages/reflection/test/reflection_test.dart
Normal 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>()),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue