Compare commits

...

2 commits

Author SHA1 Message Date
Patrick Stewart
c2a864ab38 refactor(zero): beginning feature branch 2024-11-25 20:35:42 -07:00
Patrick Stewart
f2f81f11df refactor: moved documents from docs to doc 2024-11-25 20:33:45 -07:00
731 changed files with 747 additions and 61127 deletions

View file

View file

@ -0,0 +1,96 @@
# Platform Reflection Implementation Strategy
## Overview
This document outlines the implementation strategy for Platform Reflection, a cross-platform reflection system for Dart that serves as the foundation for our Laravel implementation.
## Core Requirements
### Cross-Platform Compatibility
- Must run on all Dart targets (VM, Web, Flutter)
- No dependency on dart:mirrors
- Pure Dart implementation for maximum portability
### Runtime Capabilities Required for Laravel
- Dynamic class instantiation with constructor resolution
- Property get/set with proper type handling
- Method invocation with parameter matching
- Annotation/attribute support for Laravel decorators
- Service container bindings support
- Dependency injection resolution
- Route reflection for controllers
- Middleware reflection
- Model reflection for ORM
- Event/listener reflection
- Policy/authorization reflection
## Reference Implementation Inspirations
### From Dart Mirrors (mirrors.cc/mirrors.dart)
- Mirror hierarchy design for clean abstraction
- Symbol resolution approach
- Type information handling
- Method and constructor parameter matching
- Library and declaration organization
### From fake_reflection
- Pure runtime reflection techniques
- Dynamic instance creation patterns
- Property access mechanisms
- Method invocation strategies
## Missing Critical Features to Implement
### Core Reflection
- Dynamic member lookup without hardcoding
- Complete constructor resolution system
- Proper method parameter matching
- Type hierarchy reflection
### Laravel Support
- Service container reflection
- Controller action reflection
- Model property/relationship reflection
- Policy method reflection
- Event handler reflection
### Type System
- Generic type handling
- Interface/mixin support
- Inheritance chain resolution
- Type alias support
### Member Access
- Dynamic property access
- Flexible method invocation
- Static member support
- Proper constructor resolution
## Implementation Plan
### 1. Enhance Type System
- Implement proper type hierarchy reflection
- Add generic type support
- Support interfaces and mixins
- Handle type aliases
### 2. Improve Member Access
- Implement dynamic property access
- Add flexible method invocation
- Support static members
- Enhance constructor resolution
### 3. Add Laravel-Specific Features
- Service container reflection support
- Controller reflection capabilities
- Model reflection support
- Policy/authorization reflection
- Event system reflection
### 4. Optimize Performance
- Implement metadata caching
- Optimize member lookup
- Efficient type checking
- Smart instance creation
## Conclusion
This implementation strategy focuses on building a robust reflection system that can serve as the foundation for our Laravel implementation while maintaining cross-platform compatibility and avoiding dart:mirrors dependencies. The approach draws inspiration from established reflection implementations while addressing the specific needs of our platform.

View file

@ -1,9 +0,0 @@
library angel3_bus;
export 'src/dispatcher.dart';
export 'src/command.dart';
export 'src/handler.dart';
export 'src/queue.dart';
export 'src/batch.dart';
export 'src/chain.dart';
export 'src/bus_service_provider.dart';

View file

@ -1,19 +0,0 @@
import 'command.dart';
import 'dispatcher.dart';
class Batch {
// Implement Batch
}
class PendingBatch {
final Dispatcher _dispatcher;
final List<Command> _commands;
PendingBatch(this._dispatcher, this._commands);
Future<void> dispatch() async {
for (var command in _commands) {
await _dispatcher.dispatch(command);
}
}
}

View file

@ -1,60 +0,0 @@
// // lib/src/bus_service_provider.dart
// import 'package:angel3_framework/angel3_framework.dart';
// import 'package:angel3_event_bus/angel3_event_bus.dart';
// import 'package:angel3_mq/angel3_mq.dart';
// import 'dispatcher.dart';
// class BusServiceProvider extends Provider {
// @override
// Future<void> boot(Angel app) async {
// // Register EventBus
// app.container.registerSingleton<EventBus>(EventBus());
// // Register Queue
// app.container.registerSingleton<Queue>(MemoryQueue());
// // Create and register the Dispatcher
// final dispatcher = Dispatcher(app.container);
// app.container.registerSingleton<Dispatcher>(dispatcher);
// // Register any global middleware or mappings
// dispatcher.pipeThrough([
// // Add any global middleware here
// ]);
// // Register command-to-handler mappings
// dispatcher.map({
// // Add your command-to-handler mappings here
// // Example: ExampleCommand: ExampleCommandHandler,
// });
// }
// }
// class MemoryQueue implements Queue {
// final List<Command> _queue = [];
// @override
// Future<void> push(Command command) async {
// _queue.add(command);
// }
// @override
// Future<void> later(Duration delay, Command command) async {
// await Future.delayed(delay);
// _queue.add(command);
// }
// @override
// Future<void> pushOn(String queue, Command command) async {
// // For simplicity, ignoring the queue parameter in this implementation
// _queue.add(command);
// }
// @override
// Future<void> laterOn(String queue, Duration delay, Command command) async {
// // For simplicity, ignoring the queue parameter in this implementation
// await Future.delayed(delay);
// _queue.add(command);
// }
// }

View file

@ -1,15 +0,0 @@
import 'command.dart';
import 'dispatcher.dart';
class PendingChain {
final Dispatcher _dispatcher;
final List<Command> _commands;
PendingChain(this._dispatcher, this._commands);
Future<void> dispatch() async {
for (var command in _commands) {
await _dispatcher.dispatch(command);
}
}
}

View file

@ -1,5 +0,0 @@
// lib/src/command.dart
abstract class Command {}
abstract class ShouldQueue implements Command {}

View file

@ -1,251 +0,0 @@
// lib/src/dispatcher.dart
import 'dart:async';
import 'package:platform_container/container.dart';
import 'package:angel3_reactivex/angel3_reactivex.dart';
import 'package:angel3_event_bus/event_bus.dart';
import 'package:angel3_mq/mq.dart';
import 'command.dart';
import 'handler.dart';
import 'batch.dart';
import 'chain.dart';
/// A class that handles dispatching and processing of commands.
///
/// This dispatcher supports both synchronous and asynchronous command execution,
/// as well as queueing commands for later processing.
class Dispatcher implements QueueingDispatcher {
final Container container;
final EventBus _eventBus;
final Subject<Command> _commandSubject;
final MQClient _queue;
final Map<Type, Type> _handlers = {};
/// Creates a new [Dispatcher] instance.
///
/// [container] is used for dependency injection and to retrieve necessary services.
Dispatcher(this.container)
: _eventBus = container.make<EventBus>(),
_commandSubject = BehaviorSubject<Command>(),
_queue = container.make<MQClient>() {
_setupCommandProcessing();
}
/// Sets up the command processing pipeline.
///
/// This method initializes the stream that processes commands and emits events.
void _setupCommandProcessing() {
_commandSubject
.flatMap((command) => Stream.fromFuture(_processCommand(command))
.map((result) => CommandEvent(command, result: result))
.onErrorReturnWith(
(error, stackTrace) => CommandEvent(command, error: error)))
.listen((event) {
_eventBus.fire(event);
});
}
/// Dispatches a command for execution.
///
/// If the command implements [ShouldQueue], it will be dispatched to a queue.
/// Otherwise, it will be executed immediately.
///
/// [command] is the command to be dispatched.
@override
Future<dynamic> dispatch(Command command) {
if (command is ShouldQueue) {
return dispatchToQueue(command);
} else {
return dispatchNow(command);
}
}
/// Dispatches a command for immediate execution.
///
/// [command] is the command to be executed.
/// [handler] is an optional specific handler for the command.
@override
Future<dynamic> dispatchNow(Command command, [Handler? handler]) {
final completer = Completer<dynamic>();
_commandSubject.add(command);
_eventBus
.on<CommandEvent>()
.where((event) => event.command == command)
.take(1)
.listen((event) {
if (event.error != null) {
completer.completeError(event.error);
} else {
completer.complete(event.result);
}
});
return completer.future;
}
/// Processes a command by finding and executing its appropriate handler.
///
/// [command] is the command to be processed.
Future<dynamic> _processCommand(Command command) async {
final handlerType = _handlers[command.runtimeType];
if (handlerType != null) {
final handler = container.make(handlerType) as Handler;
return await handler.handle(command);
} else {
throw Exception('No handler found for command: ${command.runtimeType}');
}
}
/// Dispatches a command to a queue for later processing.
///
/// [command] is the command to be queued.
@override
Future<dynamic> dispatchToQueue(Command command) async {
final message = Message(
payload: command,
headers: {
'commandType': command.runtimeType.toString(),
},
);
_queue.sendMessage(
message: message,
// You might want to specify an exchange name and routing key if needed
// exchangeName: 'your_exchange_name',
// routingKey: 'your_routing_key',
);
return message.id;
}
/// Dispatches a command synchronously.
///
/// This is an alias for [dispatchNow].
///
/// [command] is the command to be executed.
/// [handler] is an optional specific handler for the command.
@override
Future<dynamic> dispatchSync(Command command, [Handler? handler]) {
return dispatchNow(command, handler);
}
/// Finds a batch by its ID.
///
/// [batchId] is the ID of the batch to find.
@override
Future<Batch?> findBatch(String batchId) async {
// Implement batch finding logic
throw UnimplementedError();
}
/// Creates a new pending batch of commands.
///
/// [commands] is the list of commands to be included in the batch.
@override
PendingBatch batch(List<Command> commands) {
return PendingBatch(this, commands);
}
/// Creates a new pending chain of commands.
///
/// [commands] is the list of commands to be included in the chain.
@override
PendingChain chain(List<Command> commands) {
return PendingChain(this, commands);
}
/// Applies a list of pipes to the command processing pipeline.
///
/// [pipes] is the list of pipes to be applied.
@override
Dispatcher pipeThrough(List<Pipe> pipes) {
_commandSubject.transform(
StreamTransformer.fromHandlers(
handleData: (data, sink) {
var result = data;
for (var pipe in pipes) {
result = pipe(result);
}
sink.add(result);
},
),
);
return this;
}
/// Maps command types to their respective handler types.
///
/// [handlers] is a map where keys are command types and values are handler types.
@override
Dispatcher map(Map<Type, Type> handlers) {
_handlers.addAll(handlers);
return this;
}
/// Dispatches a command to be executed after the current request-response cycle.
///
/// [command] is the command to be dispatched after the response.
@override
void dispatchAfterResponse(Command command) {
final message = Message(
payload: command,
headers: {
'commandType': command.runtimeType.toString(),
'dispatchAfterResponse': 'true',
},
);
_queue.sendMessage(
message: message,
// You might want to specify an exchange name if needed
// exchangeName: 'your_exchange_name',
// If you want to use a specific queue for after-response commands:
routingKey: 'after_response_queue',
);
}
}
abstract class QueueingDispatcher {
Future<dynamic> dispatch(Command command);
Future<dynamic> dispatchSync(Command command, [Handler? handler]);
Future<dynamic> dispatchNow(Command command, [Handler? handler]);
Future<dynamic> dispatchToQueue(Command command);
Future<Batch?> findBatch(String batchId);
PendingBatch batch(List<Command> commands);
PendingChain chain(List<Command> commands);
Dispatcher pipeThrough(List<Pipe> pipes);
Dispatcher map(Map<Type, Type> handlers);
void dispatchAfterResponse(Command command);
}
typedef Pipe = Command Function(Command);
class CommandCompletedEvent extends AppEvent {
final dynamic result;
CommandCompletedEvent(this.result);
@override
List<Object?> get props => [result];
}
class CommandErrorEvent extends AppEvent {
final dynamic error;
CommandErrorEvent(this.error);
@override
List<Object?> get props => [error];
}
class CommandEvent extends AppEvent {
final Command command;
final dynamic result;
final dynamic error;
CommandEvent(this.command, {this.result, this.error});
@override
List<Object?> get props => [command, result, error];
}

View file

@ -1,5 +0,0 @@
import 'command.dart';
abstract class Handler {
Future<dynamic> handle(Command command);
}

View file

@ -1,8 +0,0 @@
import 'command.dart';
abstract class Queue {
Future<void> push(Command command);
Future<void> later(Duration delay, Command command);
Future<void> pushOn(String queue, Command command);
Future<void> laterOn(String queue, Duration delay, Command command);
}

View file

@ -1,197 +0,0 @@
import 'dart:async';
import 'package:platform_bus/angel3_bus.dart';
import 'package:platform_container/container.dart';
import 'package:angel3_event_bus/event_bus.dart';
import 'package:angel3_mq/mq.dart';
import 'package:mockito/mockito.dart';
import 'package:test/test.dart';
class IsMessage extends Matcher {
@override
bool matches(item, Map matchState) => item is Message;
@override
Description describe(Description description) =>
description.add('is a Message');
}
class MockContainer extends Mock implements Container {
final Map<Type, dynamic> _instances = {};
@override
T make<T>([Type? type]) {
type ??= T;
return _instances[type] as T;
}
void registerInstance<T>(T instance) {
_instances[T] = instance;
}
}
class MockEventBus extends Mock implements EventBus {
@override
Stream<T> on<T extends AppEvent>() {
return super.noSuchMethod(
Invocation.method(#on, [], {#T: T}),
returnValue: Stream<T>.empty(),
) as Stream<T>;
}
}
class MockMQClient extends Mock implements MQClient {
Message? capturedMessage;
String? capturedExchangeName;
String? capturedRoutingKey;
@override
dynamic noSuchMethod(Invocation invocation,
{Object? returnValue, Object? returnValueForMissingStub}) {
if (invocation.memberName == #sendMessage) {
final namedArgs = invocation.namedArguments;
capturedMessage = namedArgs[#message] as Message?;
capturedExchangeName = namedArgs[#exchangeName] as String?;
capturedRoutingKey = namedArgs[#routingKey] as String?;
return null;
}
return super.noSuchMethod(invocation,
returnValue: returnValue,
returnValueForMissingStub: returnValueForMissingStub);
}
}
class TestCommand implements Command {
final String data;
TestCommand(this.data);
}
class TestHandler implements Handler {
@override
Future<dynamic> handle(Command command) async {
if (command is TestCommand) {
return 'Handled: ${command.data}';
}
throw UnimplementedError();
}
}
class TestQueuedCommand implements Command, ShouldQueue {
final String data;
TestQueuedCommand(this.data);
}
void main() {
late MockContainer container;
late MockEventBus eventBus;
late MockMQClient mqClient;
late Dispatcher dispatcher;
setUp(() {
container = MockContainer();
eventBus = MockEventBus();
mqClient = MockMQClient();
container.registerInstance<EventBus>(eventBus);
container.registerInstance<MQClient>(mqClient);
dispatcher = Dispatcher(container);
});
group('Dispatcher', () {
test('dispatchNow should handle command and return result', () async {
final command = TestCommand('test data');
final handler = TestHandler();
container.registerInstance<TestHandler>(handler);
dispatcher.map({TestCommand: TestHandler});
final commandEventController = StreamController<CommandEvent>();
when(eventBus.on<CommandEvent>())
.thenAnswer((_) => commandEventController.stream);
final future = dispatcher.dispatchNow(command);
// Simulate the event firing
commandEventController
.add(CommandEvent(command, result: 'Handled: test data'));
final result = await future;
expect(result, equals('Handled: test data'));
await commandEventController.close();
});
test('dispatch should handle regular commands immediately', () async {
final command = TestCommand('regular');
final handler = TestHandler();
container.registerInstance<TestHandler>(handler);
dispatcher.map({TestCommand: TestHandler});
final commandEventController = StreamController<CommandEvent>();
when(eventBus.on<CommandEvent>())
.thenAnswer((_) => commandEventController.stream);
final future = dispatcher.dispatch(command);
// Simulate the event firing
commandEventController
.add(CommandEvent(command, result: 'Handled: regular'));
final result = await future;
expect(result, equals('Handled: regular'));
await commandEventController.close();
});
test('dispatch should queue ShouldQueue commands', () async {
final command = TestQueuedCommand('queued data');
// Dispatch the command
await dispatcher.dispatch(command);
// Verify that sendMessage was called and check the message properties
expect(mqClient.capturedMessage, isNotNull);
expect(mqClient.capturedMessage!.payload, equals(command));
expect(mqClient.capturedMessage!.headers?['commandType'],
equals('TestQueuedCommand'));
// Optionally, verify exchange name and routing key if needed
expect(mqClient.capturedExchangeName, isNull);
expect(mqClient.capturedRoutingKey, isNull);
});
test(
'dispatchAfterResponse should send message to queue with specific header',
() {
final command = TestCommand('after response data');
// Call dispatchAfterResponse
dispatcher.dispatchAfterResponse(command);
// Verify that sendMessage was called and check the message properties
expect(mqClient.capturedMessage, isNotNull);
expect(mqClient.capturedMessage!.payload, equals(command));
expect(mqClient.capturedMessage!.headers?['commandType'],
equals('TestCommand'));
expect(mqClient.capturedMessage!.headers?['dispatchAfterResponse'],
equals('true'));
// Verify routing key
expect(mqClient.capturedRoutingKey, equals('after_response_queue'));
// Optionally, verify exchange name if needed
expect(mqClient.capturedExchangeName, isNull);
});
test('map should register command handlers', () {
dispatcher.map({TestCommand: TestHandler});
// Mock the event bus behavior for this test
when(eventBus.on<CommandEvent>()).thenAnswer((_) => Stream.empty());
// This test is a bit tricky to verify directly, but we can check if dispatch doesn't throw
expect(() => dispatcher.dispatch(TestCommand('test')), returnsNormally);
});
});
}

View file

View file

View file

View file

@ -1,18 +1,16 @@
name: platform_pipeline name: platform_config
description: The Pipeline Package for the Protevus Platform description: The Configuration Package for the Protevus Platform
version: 0.0.1 version: 0.0.1
homepage: https://protevus.com homepage: https://protevus.com
documentation: https://docs.protevus.com documentation: https://docs.protevus.com
repository: https://github.com/protevus/platform repository: https://git.protevus.com/protevus/platform
environment: environment:
sdk: ^3.4.2 sdk: ^3.4.2
# Add regular dependencies here. # Add regular dependencies here.
dependencies: dependencies:
platform_container: ^9.0.0 #protevus_runtime: ^0.0.1
platform_core: ^9.0.0
logging: ^1.1.0
dev_dependencies: dev_dependencies:
lints: ^3.0.0 lints: ^3.0.0

View file

View file

@ -1,71 +0,0 @@
# See https://www.dartlang.org/tools/private-files.html
# Files and directories created by pub
.dart_tool
.packages
.pub/
build/
# If you're building an application, you may want to check-in your pubspec.lock
pubspec.lock
# Directory created by dartdoc
# If you don't generate documentation locally you can remove this line.
doc/api/
### Dart template
# See https://www.dartlang.org/tools/private-files.html
# Files and directories created by pub
# SDK 1.20 and later (no longer creates packages directories)
# Older SDK versions
# (Include if the minimum SDK version specified in pubsepc.yaml is earlier than 1.20)
.project
.buildlog
**/packages/
# Files created by dart2js
# (Most Dart developers will use pub build to compile Dart, use/modify these
# rules if you intend to use dart2js directly
# Convention is to use extension '.dart.js' for Dart compiled to Javascript to
# differentiate from explicit Javascript files)
*.dart.js
*.part.js
*.js.deps
*.js.map
*.info.json
# Directory created by dartdoc
# Don't commit pubspec lock file
# (Library packages only! Remove pattern if developing an application package)
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff:
## VsCode
.vscode/
## File-based project format:
*.iws
## Plugin-specific files:
# IntelliJ
.idea/
/out/
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties

View file

@ -1,12 +0,0 @@
Primary Authors
===============
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
Thomas is the current maintainer of the code base. He has refactored and migrated the
code base to support NNBD.
* __[Tobe O](thosakwe@gmail.com)__
Tobe has written much of the original code prior to NNBD migration. He has moved on and
is no longer involved with the project.

View file

@ -1,151 +0,0 @@
# Change Log
## 8.1.1
* Updated repository link
## 8.1.0
* Updated `lints` to 3.0.0
* Fixed analyser warnings
## 8.0.0
* Require Dart >= 3.0
## 7.1.0-beta.2
* Require Dart >= 2.19
* Refactored `EmptyReflector`
## 7.1.0-beta.1
* Require Dart >= 2.18
* Moved `defaultErrorMessage` to `ContainerConst` class to resolve reflectatable issue.
* Added `hashCode`
## 7.0.0
* Require Dart >= 2.17
## 6.0.0
* Require Dart >= 2.16
* Removed `error`
## 5.0.0
* Skipped release
## 4.0.0
* Skipped release
## 3.1.1
* Updated `_ReflectedMethodMirror` to have optional `returnType` parameter
* Updated `Container` to handle non nullable type
## 3.1.0
* Updated linter to `package:lints`
## 3.0.2
* Resolved static analysis warnings
## 3.0.1
* Updated README
## 3.0.0
* Migrated to support Dart >= 2.12 NNBD
## 2.0.0
* Migrated to work with Dart >= 2.12 Non NNBD
## 1.1.0
* `pedantic` lints.
* Add `ThrowingReflector`, which throws on all operations.
* `EmptyReflector` uses `Object` instead of `dynamic` as its returned
type, as the `dynamic` type is (apparently?) no longer a valid constant value.
* `registerSingleton` now returns the provided `object`.
* `registerFactory` and `registerLazySingleton` now return the provided function `f`.
## 1.0.4
* Slight patch to prevent annoying segfault.
## 1.0.3
* Added `Future` support to `Reflector`.
## 1.0.2
* Added `makeAsync<T>`.
## 1.0.1
* Added `hasNamed`.
## 1.0.0
* Removed `@GenerateReflector`.
## 1.0.0-alpha.12
* `StaticReflector` now defaults to empty arguments.
## 1.0.0-alpha.11
* Added `StaticReflector`.
## 1.0.0-alpha.10
* Added `Container.registerLazySingleton<T>`.
* Added named singleton support.
## 1.0.0-alpha.9
* Added `Container.has<T>`.
## 1.0.0-alpha.8
* Fixed a bug where `_ReflectedTypeInstance.isAssignableTo` always failed.
* Added `@GenerateReflector` annotation.
## 1.0.0-alpha.7
* Add `EmptyReflector`.
* `ReflectedType.newInstance` now returns a `ReflectedInstance`.
* Moved `ReflectedInstance.invoke` to `ReflectedFunction.invoke`.
## 1.0.0-alpha.6
* Add `getField` to `ReflectedInstance`.
## 1.0.0-alpha.5
* Remove concrete type from `ReflectedTypeParameter`.
## 1.0.0-alpha.4
* Safely handle `void` return types of methods.
## 1.0.0-alpha.3
* Reflecting `void` in `MirrorsReflector` now forwards to `dynamic`.
## 1.0.0-alpha.2
* Added `ReflectedInstance.reflectee`.
## 1.0.0-alpha.1
* Allow omission of the first argument of `Container.make`, to use
a generic type argument instead.
* `singleton` -> `registerSingleton`
* Add `createChild`, and support hierarchical containers.

View file

@ -1,29 +0,0 @@
BSD 3-Clause License
Copyright (c) 2021, dukefirehawk.com
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,45 +0,0 @@
# Protevus Container
![Pub Version (including pre-releases)](https://img.shields.io/pub/v/platform_container?include_prereleases)
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion)
[![License](https://img.shields.io/github/license/dart-backend/angel)](https://github.com/dart-backend/angel/tree/master/packages/container/angel_container/LICENSE)
A better IoC container for Protevus, ultimately allowing Protevus to be used with or without `dart:mirrors` package.
```dart
import 'package:platform_container/mirrors.dart';
import 'package:platform_core/core.dart';
import 'package:platform_core/http.dart';
@Expose('/sales', middleware: [process1])
class SalesController extends Controller {
@Expose('/', middleware: [process2])
Future<String> route1(RequestContext req, ResponseContext res) async {
return "Sales route";
}
}
bool process1(RequestContext req, ResponseContext res) {
res.write('Hello, ');
return true;
}
bool process2(RequestContext req, ResponseContext res) {
res.write('From Sales, ');
return true;
}
void main() async {
// Using Mirror Reflector
var app = Protevus(reflector: MirrorsReflector());
// Sales Controller
app.container.registerSingleton<SalesController>(SalesController());
await app.mountController<SalesController>();
var http = PlatformHttp(app);
var server = await http.startServer('localhost', 3000);
print("Protevus server listening at ${http.uri}");
}
```

View file

@ -1 +0,0 @@
include: package:lints/recommended.yaml

View file

@ -1,75 +0,0 @@
import 'dart:async';
import 'package:platform_container/container.dart';
import 'package:platform_container/mirrors.dart';
Future<void> main() async {
// Create a container instance.
var container = Container(const MirrorsReflector());
// Register a singleton.
container.registerSingleton<Engine>(Engine(40));
// You can also omit the type annotation, in which the object's runtime type will be used.
// If you're injecting an abstract class, prefer the type annotation.
//
// container.registerSingleton(Engine(40));
// Register a factory that creates a truck.
container.registerFactory<Truck>((container) {
return _TruckImpl(container.make<Engine>());
});
// Use `make` to create an instance.
var truck = container.make<Truck>();
// You can also resolve injections asynchronously.
container.registerFactory<Future<int>>((_) async => 24);
print(await container.makeAsync<int>());
// Asynchronous resolution also works for plain objects.
await container.makeAsync<Truck>().then((t) => t.drive());
// Register a named singleton.
container.registerNamedSingleton('the_truck', truck);
// Should print: 'Vroom! I have 40 horsepower in my engine.'
truck.drive();
// Should print the same.
container.findByName<Truck>('the_truck').drive();
// We can make a child container with its own factory.
var childContainer = container.createChild();
childContainer.registerFactory<Truck>((container) {
return _TruckImpl(Engine(5666));
});
// Make a truck with 5666 HP.
childContainer.make<Truck>().drive();
// However, calling `make<Engine>` will return the Engine singleton we created above.
print(childContainer.make<Engine>().horsePower);
}
abstract class Truck {
void drive();
}
class Engine {
final int horsePower;
Engine(this.horsePower);
}
class _TruckImpl implements Truck {
final Engine engine;
_TruckImpl(this.engine);
@override
void drive() {
print('Vroom! I have ${engine.horsePower} horsepower in my engine.');
}
}

View file

@ -1,6 +0,0 @@
import 'package:platform_container/container.dart';
void main() {
var reflector = const ThrowingReflector();
reflector.reflectClass(StringBuffer);
}

View file

@ -1,18 +0,0 @@
/*
* 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.
*/
library platform_container;
export 'src/container.dart';
export 'src/empty/empty.dart';
export 'src/static/static.dart';
export 'src/exception.dart';
export 'src/reflector.dart';
export 'src/throwing.dart';
export 'src/container_const.dart';

View file

@ -1,10 +0,0 @@
/*
* 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.
*/
export 'src/mirrors/mirrors.dart';

View file

@ -1,396 +0,0 @@
/*
* 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 'dart:async';
import 'exception.dart';
import 'reflector.dart';
class Container {
/// The [Reflector] instance used by this container for reflection-based operations.
///
/// This reflector is used to instantiate objects and resolve dependencies
/// when no explicit factory or singleton is registered for a given type.
final Reflector reflector;
/// A map that stores singleton instances, where the key is the Type and the value is the singleton object.
///
/// This map is used internally by the Container to store and retrieve singleton objects
/// that have been registered using the [registerSingleton] method.
final Map<Type, dynamic> _singletons = {};
/// A map that stores factory functions for creating instances of different types.
///
/// The key is the Type for which the factory is registered, and the value is a function
/// that takes a Container as an argument and returns an instance of that Type.
///
/// This map is used internally by the Container to store and retrieve factory functions
/// that have been registered using the [registerFactory] method.
final Map<Type, dynamic Function(Container)> _factories = {};
/// A map that stores named singleton instances, where the key is a String name and the value is the singleton object.
///
/// This map is used internally by the Container to store and retrieve named singleton objects
/// that have been registered using the [registerNamedSingleton] method. Named singletons allow
/// for multiple instances of the same type to be stored in the container with different names.
final Map<String, dynamic> _namedSingletons = {};
/// The parent container of this container, if any.
///
/// This property is used to create a hierarchy of containers, where child containers
/// can access dependencies registered in their parent containers. If this container
/// is a root container (i.e., it has no parent), this property will be null.
///
/// The parent-child relationship allows for scoped dependency injection, where
/// child containers can override or add to the dependencies defined in their parents.
final Container? _parent;
/// Creates a new root [Container] instance with the given [Reflector].
///
/// This constructor initializes a new container without a parent, making it
/// a root container in the dependency injection hierarchy. The provided
/// [reflector] will be used for all reflection-based operations within this
/// container and its child containers.
///
/// Parameters:
/// - [reflector]: The [Reflector] instance to be used by this container
/// for reflection-based dependency resolution and object instantiation.
///
/// The [_parent] is set to null, indicating that this is a root container.
Container(this.reflector) : _parent = null;
/// Creates a child [Container] instance with the given parent container.
///
/// This constructor is used internally to create child containers in the
/// dependency injection hierarchy. It initializes a new container with a
/// reference to its parent container and uses the same [Reflector] instance
/// as the parent.
///
/// Parameters:
/// - [_parent]: The parent [Container] instance for this child container.
///
/// The [reflector] is initialized with the parent container's reflector,
/// ensuring consistency in reflection operations throughout the container
/// hierarchy.
Container._child(Container this._parent) : reflector = _parent.reflector;
/// Checks if this container is a root container.
///
/// Returns `true` if this container has no parent (i.e., it's a root container),
/// and `false` otherwise.
///
/// This property is useful for determining the position of a container in the
/// dependency injection hierarchy. Root containers are typically used as the
/// top-level containers in an application, while non-root containers are child
/// containers that may have more specific or localized dependencies.
bool get isRoot => _parent == null;
/// Creates a child [Container] that can define its own singletons and factories.
///
/// This method creates a new [Container] instance that is a child of the current container.
/// The child container inherits access to all dependencies registered in its parent containers,
/// but can also define its own singletons and factories that override or extend the parent's dependencies.
///
/// Child containers are useful for creating scoped dependency injection contexts, such as
/// for specific features, modules, or request-scoped dependencies in web applications.
///
/// The child container uses the same [Reflector] instance as its parent.
///
/// Returns:
/// A new [Container] instance that is a child of the current container.
///
/// Example:
/// ```dart
/// var parentContainer = Container(MyReflector());
/// var childContainer = parentContainer.createChild();
/// ```
Container createChild() {
return Container._child(this);
}
/// Determines if the container or any of its parent containers has an injection of the given type.
///
/// This method checks for both singleton and factory registrations of the specified type.
///
/// Parameters:
/// - [T]: The type to check for. If [T] is dynamic, the [t] parameter must be provided.
/// - [t]: An optional Type parameter. If provided, it overrides the type specified by [T].
///
/// Returns:
/// - `true` if an injection (singleton or factory) for the specified type is found in this
/// container or any of its parent containers.
/// - `false` if no injection is found for the specified type in the entire container hierarchy.
///
/// Note:
/// - If [T] is dynamic and [t] is null, the method returns `false` immediately.
/// - The method searches the current container first, then moves up the parent hierarchy
/// until an injection is found or the root container is reached.
bool has<T>([Type? t]) {
var t2 = T;
if (t != null) {
t2 = t;
} else if (T == dynamic && t == null) {
return false;
}
Container? search = this;
while (search != null) {
if (search._singletons.containsKey(t2)) {
return true;
} else if (search._factories.containsKey(t2)) {
return true;
} else {
search = search._parent;
}
}
return false;
}
/// Determines if the container or any of its parent containers has a named singleton with the given [name].
///
/// This method searches the current container and its parent hierarchy for a named singleton
/// registered with the specified [name].
///
/// Parameters:
/// - [name]: The name of the singleton to search for.
///
/// Returns:
/// - `true` if a named singleton with the specified [name] is found in this container
/// or any of its parent containers.
/// - `false` if no named singleton with the specified [name] is found in the entire
/// container hierarchy.
///
/// The method searches the current container first, then moves up the parent hierarchy
/// until a named singleton is found or the root container is reached.
bool hasNamed(String name) {
Container? search = this;
while (search != null) {
if (search._namedSingletons.containsKey(name)) {
return true;
} else {
search = search._parent;
}
}
return false;
}
/// Asynchronously instantiates an instance of [T].
///
/// This method attempts to resolve and return a [Future<T>] in the following order:
/// 1. If an injection of type [T] is registered, it wraps it in a [Future] and returns it.
/// 2. If an injection of type [Future<T>] is registered, it returns it directly.
/// 3. If [T] is [dynamic] and a [Future] of the specified type is registered, it returns that.
/// 4. If none of the above conditions are met, it throws a [ReflectionException].
///
/// Parameters:
/// - [type]: An optional [Type] parameter that can be used to specify the type
/// when [T] is [dynamic] or when a different type than [T] needs to be used.
///
/// Returns:
/// A [Future<T>] representing the asynchronously resolved instance.
///
/// Throws:
/// - [ReflectionException] if no suitable injection is found.
///
/// This method is useful when you need to resolve dependencies that may be
/// registered as either synchronous ([T]) or asynchronous ([Future<T>]) types.
Future<T> makeAsync<T>([Type? type]) {
var t2 = T;
if (type != null) {
t2 = type;
}
Type? futureType; //.Future<T>.value(null).runtimeType;
if (T == dynamic) {
try {
futureType = reflector.reflectFutureOf(t2).reflectedType;
} on UnsupportedError {
// Ignore this.
}
}
if (has<T>(t2)) {
return Future<T>.value(make(t2));
} else if (has<Future<T>>()) {
return make<Future<T>>();
} else if (futureType != null) {
return make(futureType);
} else {
throw ReflectionException(
'No injection for Future<$t2> or $t2 was found.');
}
}
/// Instantiates an instance of [T].
///
/// This method attempts to resolve and return an instance of type [T] in the following order:
/// 1. If a singleton of type [T] is registered in this container or any parent container, it returns that instance.
/// 2. If a factory for type [T] is registered in this container or any parent container, it calls the factory and returns the result.
/// 3. If no singleton or factory is found, it uses reflection to instantiate a new instance of [T].
///
/// For reflection-based instantiation:
/// - It looks for a default constructor or a constructor with an empty name.
/// - It recursively resolves and injects dependencies for the constructor parameters.
/// - It supports both positional and named parameters.
///
/// Parameters:
/// - [type]: An optional [Type] parameter that can be used to specify the type
/// when [T] is [dynamic] or when a different type than [T] needs to be used.
///
/// Returns:
/// An instance of type [T].
///
/// Throws:
/// - [ReflectionException] if [T] is not a class or if it has no default constructor.
/// - Any exception that might occur during the instantiation process.
///
/// This method is central to the dependency injection mechanism, allowing for
/// flexible object creation and dependency resolution within the container hierarchy.
T make<T>([Type? type]) {
Type t2 = T;
if (type != null) {
t2 = type;
}
Container? search = this;
while (search != null) {
if (search._singletons.containsKey(t2)) {
// Find a singleton, if any.
return search._singletons[t2] as T;
} else if (search._factories.containsKey(t2)) {
// Find a factory, if any.
return search._factories[t2]!(this) as T;
} else {
search = search._parent;
}
}
var reflectedType = reflector.reflectType(t2);
var positional = [];
var named = <String, Object>{};
if (reflectedType is ReflectedClass) {
bool isDefault(String name) {
return name.isEmpty || name == reflectedType.name;
}
var constructor = reflectedType.constructors.firstWhere(
(c) => isDefault(c.name),
orElse: (() => throw ReflectionException(
'${reflectedType.name} has no default constructor, and therefore cannot be instantiated.')));
for (var param in constructor.parameters) {
var value = make(param.type.reflectedType);
if (param.isNamed) {
named[param.name] = value;
} else {
positional.add(value);
}
}
return reflectedType.newInstance(
isDefault(constructor.name) ? '' : constructor.name,
positional,
named, []).reflectee as T;
} else {
throw ReflectionException(
'$t2 is not a class, and therefore cannot be instantiated.');
}
}
/// Registers a lazy singleton factory.
///
/// In many cases, you might prefer this to [registerFactory].
///
/// Returns [f].
T Function(Container) registerLazySingleton<T>(T Function(Container) f,
{Type? as}) {
return registerFactory<T>(
(container) {
var r = f(container);
container.registerSingleton<T>(r, as: as);
return r;
},
as: as,
);
}
/// Registers a factory function for creating instances of type [T] in the container.
///
/// Returns [f].
T Function(Container) registerFactory<T>(T Function(Container) f,
{Type? as}) {
Type t2 = T;
if (as != null) {
t2 = as;
}
if (_factories.containsKey(t2)) {
throw StateError('This container already has a factory for $t2.');
}
_factories[t2] = f;
return f;
}
/// Registers a singleton object in the container.
///
/// Returns [object].
T registerSingleton<T>(T object, {Type? as}) {
Type t2 = T;
if (as != null) {
t2 = as;
} else if (T == dynamic) {
t2 = as ?? object.runtimeType;
}
//as ??= T == dynamic ? as : T;
if (_singletons.containsKey(t2)) {
throw StateError('This container already has a singleton for $t2.');
}
_singletons[t2] = object;
return object;
}
/// Retrieves a named singleton from the container or its parent containers.
///
/// In general, prefer using [registerSingleton] and [registerFactory].
///
/// [findByName] is best reserved for internal logic that end users of code should
/// not see.
T findByName<T>(String name) {
if (_namedSingletons.containsKey(name)) {
return _namedSingletons[name] as T;
} else if (_parent != null) {
return _parent.findByName<T>(name);
} else {
throw StateError(
'This container does not have a singleton named "$name".');
}
}
/// Registers a named singleton object in the container.
///
/// Note that this is not related to type-based injections, and exists as a mechanism
/// to enable injecting multiple instances of a type within the same container hierarchy.
T registerNamedSingleton<T>(String name, T object) {
if (_namedSingletons.containsKey(name)) {
throw StateError('This container already has a singleton named "$name".');
}
_namedSingletons[name] = object;
return object;
}
}

View file

@ -1,31 +0,0 @@
/*
* 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.
*/
/// A utility class that contains constant values related to container functionality.
///
/// This class is not meant to be instantiated and only provides static constants.
/// It includes a default error message for reflection-related issues.
class ContainerConst {
/// The default error message for reflection-related issues.
///
/// This message is used when an attempt is made to perform a reflective action,
/// but the `ThrowingReflector` class is being used, which disables reflection.
/// Consider using the `MirrorsReflector` class if reflection is necessary.
static const String defaultErrorMessage =
'You attempted to perform a reflective action, but you are using `ThrowingReflector`, '
'a class which disables reflection. Consider using the `MirrorsReflector` '
'class if you need reflection.';
/// Private constructor to prevent instantiation of this utility class.
///
/// This constructor is marked as private (with the underscore prefix) to ensure
/// that the `ContainerConst` class cannot be instantiated. This is consistent
/// with the class's purpose of only providing static constants.
ContainerConst._();
}

View file

@ -1,377 +0,0 @@
/*
* 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 'package:platform_container/container.dart';
/// A cache to store symbol names.
///
/// This map associates [Symbol] objects with their corresponding string representations.
/// It's used to avoid repeated parsing of symbol names, improving performance
/// when retrieving symbol names multiple times.
final Map<Symbol, String?> _symbolNames = <Symbol, String?>{};
/// A [Reflector] implementation that performs no actual reflection,
/// instead returning empty objects on every invocation.
///
/// Use this in contexts where you know you won't need any reflective capabilities.
///
/// This class provides a lightweight alternative to full reflection when reflection
/// functionality is not required. It returns empty or placeholder objects for all
/// reflection operations, which can be useful in scenarios where reflection is
/// expected but not actually used, or when you want to minimize the overhead of
/// reflection in certain parts of your application.
///
/// The [EmptyReflector] includes:
/// - A static [RegExp] for extracting symbol names without reflection.
/// - Methods to return empty implementations of [ReflectedClass], [ReflectedInstance],
/// [ReflectedType], and [ReflectedFunction].
/// - A [getName] method that uses a cache to store and retrieve symbol names.
///
/// This implementation can be particularly useful in testing scenarios or in
/// production environments where reflection is not needed but the interface
/// expecting reflection capabilities needs to be satisfied.
class EmptyReflector extends Reflector {
/// A [RegExp] that can be used to extract the name of a symbol without reflection.
///
/// This regular expression pattern matches the string representation of a Dart [Symbol],
/// which typically looks like 'Symbol("symbolName")'. It captures the symbol name
/// (the part between the quotes) in a capturing group.
///
/// Usage:
/// ```dart
/// String symbolString = 'Symbol("exampleSymbol")';
/// Match? match = symbolRegex.firstMatch(symbolString);
/// String? symbolName = match?.group(1); // Returns "exampleSymbol"
/// ```
///
/// This is particularly useful in contexts where reflection is not available
/// or desired, allowing for symbol name extraction through string manipulation.
static final RegExp symbolRegex = RegExp(r'Symbol\("([^"]+)"\)');
/// Creates an instance of [EmptyReflector].
///
/// This constructor doesn't take any parameters and creates a lightweight
/// reflector that provides empty implementations for all reflection operations.
/// It's useful in scenarios where reflection capabilities are expected but not
/// actually used, or when you want to minimize the overhead of reflection.
const EmptyReflector();
/// Retrieves the name of a given [Symbol].
///
/// This method attempts to extract the name of the provided [symbol] using
/// the [symbolRegex]. If the name hasn't been cached before, it will be
/// computed and stored in the [_symbolNames] cache for future use.
///
/// The method works as follows:
/// 1. It checks if the symbol's name is already in the cache.
/// 2. If not found, it uses [putIfAbsent] to compute the name:
/// a. It converts the symbol to a string.
/// b. It applies the [symbolRegex] to extract the name.
/// c. If a match is found, it returns the first captured group (the name).
/// 3. The computed name (or null if not found) is stored in the cache and returned.
///
/// @param symbol The [Symbol] whose name is to be retrieved.
/// @return The name of the symbol as a [String], or null if the name couldn't be extracted.
@override
String? getName(Symbol symbol) {
return _symbolNames.putIfAbsent(
symbol, () => symbolRegex.firstMatch(symbol.toString())?.group(1));
}
/// Returns an empty [ReflectedClass] instance for any given [Type].
///
/// This method is part of the [EmptyReflector] implementation and always
/// returns a constant instance of [_EmptyReflectedClass], regardless of
/// the input [clazz].
///
/// This behavior is consistent with the purpose of [EmptyReflector],
/// which provides non-functional placeholders for reflection operations.
///
/// @param clazz The [Type] to reflect, which is ignored in this implementation.
/// @return A constant [_EmptyReflectedClass] instance.
@override
ReflectedClass reflectClass(Type clazz) {
return const _EmptyReflectedClass();
}
/// Returns an empty [ReflectedInstance] for any given object.
///
/// This method is part of the [EmptyReflector] implementation and always
/// returns a constant instance of [_EmptyReflectedInstance], regardless of
/// the input [object].
///
/// This behavior is consistent with the purpose of [EmptyReflector],
/// which provides non-functional placeholders for reflection operations.
///
/// @param object The object to reflect, which is ignored in this implementation.
/// @return A constant [_EmptyReflectedInstance].
@override
ReflectedInstance reflectInstance(Object object) {
return const _EmptyReflectedInstance();
}
/// Returns an empty [ReflectedType] for any given [Type].
///
/// This method is part of the [EmptyReflector] implementation and always
/// returns a constant instance of [_EmptyReflectedType], regardless of
/// the input [type].
///
/// This behavior is consistent with the purpose of [EmptyReflector],
/// which provides non-functional placeholders for reflection operations.
///
/// @param type The [Type] to reflect, which is ignored in this implementation.
/// @return A constant [_EmptyReflectedType] instance.
@override
ReflectedType reflectType(Type type) {
return const _EmptyReflectedType();
}
/// Returns an empty [ReflectedFunction] for any given [Function].
///
/// This method is part of the [EmptyReflector] implementation and always
/// returns a constant instance of [_EmptyReflectedFunction], regardless of
/// the input [function].
///
/// This behavior is consistent with the purpose of [EmptyReflector],
/// which provides non-functional placeholders for reflection operations.
///
/// @param function The [Function] to reflect, which is ignored in this implementation.
/// @return A constant [_EmptyReflectedFunction] instance.
@override
ReflectedFunction reflectFunction(Function function) {
return const _EmptyReflectedFunction();
}
}
/// An empty implementation of [ReflectedClass] used by [EmptyReflector].
///
/// This class provides a non-functional placeholder for reflection operations
/// on classes. It is designed to be used in contexts where reflection capabilities
/// are expected but not actually needed or desired.
///
/// Key features:
/// - Extends [ReflectedClass] with minimal implementation.
/// - Constructor initializes with empty or default values for all properties.
/// - [newInstance] method throws an [UnsupportedError] if called.
/// - [isAssignableTo] method only returns true if compared with itself.
///
/// This implementation is consistent with the purpose of [EmptyReflector],
/// providing a lightweight alternative when full reflection capabilities are not required.
class _EmptyReflectedClass extends ReflectedClass {
/// Constructs an empty [_EmptyReflectedClass] instance.
///
/// This constructor initializes the instance with empty or default values for all properties.
///
/// @param name The name of the class, set to '(empty)'.
/// @param typeParameters The list of type parameters, set to an empty list.
/// @param instances The list of instances, set to an empty list.
/// @param functions The list of functions, set to an empty list.
/// @param declarations The list of declarations, set to an empty list.
/// @param type The underlying [Type] of the class, set to [Object].
const _EmptyReflectedClass()
: super(
'(empty)',
const <ReflectedTypeParameter>[],
const <ReflectedInstance>[],
const <ReflectedFunction>[],
const <ReflectedDeclaration>[],
Object);
/// Creates a new instance of the reflected class.
///
/// This method is part of the [_EmptyReflectedClass] implementation and always
/// throws an [UnsupportedError] when called. This behavior is consistent with
/// the purpose of [EmptyReflector], which provides non-functional placeholders
/// for reflection operations.
///
/// @param constructorName The name of the constructor to invoke.
/// @param positionalArguments A list of positional arguments for the constructor.
/// @param namedArguments An optional map of named arguments for the constructor.
/// @param typeArguments An optional list of type arguments for generic classes.
/// @throws UnsupportedError Always thrown when this method is called.
/// @return This method never returns as it always throws an exception.
@override
ReflectedInstance newInstance(
String constructorName, List positionalArguments,
[Map<String, dynamic>? namedArguments, List<Type>? typeArguments]) {
throw UnsupportedError(
'Classes reflected via an EmptyReflector cannot be instantiated.');
}
/// Checks if this empty reflected class is assignable to another reflected type.
///
/// This method is part of the [_EmptyReflectedClass] implementation and always
/// returns true only if the [other] type is the same instance as this one.
/// This behavior is consistent with the purpose of [EmptyReflector],
/// which provides minimal functionality for reflection operations.
///
/// @param other The [ReflectedType] to check against.
/// @return true if [other] is the same instance as this, false otherwise.
@override
bool isAssignableTo(ReflectedType? other) {
return other == this;
}
}
/// An empty implementation of [ReflectedType] used by [EmptyReflector].
///
/// This class provides a non-functional placeholder for reflection operations
/// on types. It is designed to be used in contexts where reflection capabilities
/// are expected but not actually needed or desired.
///
/// Key features:
/// - Extends [ReflectedType] with minimal implementation.
/// - Constructor initializes with empty or default values for all properties.
/// - [newInstance] method throws an [UnsupportedError] if called.
/// - [isAssignableTo] method only returns true if compared with itself.
///
/// This implementation is consistent with the purpose of [EmptyReflector],
/// providing a lightweight alternative when full reflection capabilities are not required.
class _EmptyReflectedType extends ReflectedType {
/// Constructs an empty [_EmptyReflectedType] instance.
///
/// This constructor initializes the instance with empty or default values for all properties.
///
/// @param name The name of the type, set to '(empty)'.
/// @param typeParameters The list of type parameters, set to an empty list.
/// @param type The underlying [Type], set to [Object].
const _EmptyReflectedType()
: super('(empty)', const <ReflectedTypeParameter>[], Object);
/// Creates a new instance of the reflected type.
///
/// This method is part of the [_EmptyReflectedType] implementation and always
/// throws an [UnsupportedError] when called. This behavior is consistent with
/// the purpose of [EmptyReflector], which provides non-functional placeholders
/// for reflection operations.
///
/// @param constructorName The name of the constructor to invoke.
/// @param positionalArguments A list of positional arguments for the constructor.
/// @param namedArguments An optional map of named arguments for the constructor.
/// @param typeArguments An optional list of type arguments for generic types.
/// @throws UnsupportedError Always thrown when this method is called.
/// @return This method never returns as it always throws an exception.
@override
ReflectedInstance newInstance(
String constructorName, List positionalArguments,
[Map<String, dynamic> namedArguments = const {},
List<Type> typeArguments = const []]) {
throw UnsupportedError(
'Types reflected via an EmptyReflector cannot be instantiated.');
}
/// Checks if this empty reflected type is assignable to another reflected type.
///
/// This method is part of the [_EmptyReflectedType] implementation and always
/// returns true only if the [other] type is the same instance as this one.
/// This behavior is consistent with the purpose of [EmptyReflector],
/// which provides minimal functionality for reflection operations.
///
/// @param other The [ReflectedType] to check against.
/// @return true if [other] is the same instance as this, false otherwise.
@override
bool isAssignableTo(ReflectedType? other) {
return other == this;
}
}
/// An empty implementation of [ReflectedInstance] used by [EmptyReflector].
///
/// This class provides a non-functional placeholder for reflection operations
/// on instances. It is designed to be used in contexts where reflection capabilities
/// are expected but not actually needed or desired.
///
/// Key features:
/// - Extends [ReflectedInstance] with minimal implementation.
/// - Constructor initializes with empty or default values for all properties.
/// - [getField] method throws an [UnsupportedError] if called.
///
/// This implementation is consistent with the purpose of [EmptyReflector],
/// providing a lightweight alternative when full reflection capabilities are not required.
class _EmptyReflectedInstance extends ReflectedInstance {
/// Constructs an empty [_EmptyReflectedInstance] instance.
///
/// This constructor initializes the instance with empty or default values for all properties.
///
/// @param type The reflected type of the instance, set to an empty [_EmptyReflectedType].
/// @param reflectedClass The reflected class of the instance, set to an empty [_EmptyReflectedClass].
/// @param value The underlying value of the instance, set to null.
const _EmptyReflectedInstance()
: super(const _EmptyReflectedType(), const _EmptyReflectedClass(), null);
/// Retrieves the value of a field on this empty reflected instance.
///
/// This method is part of the [_EmptyReflectedInstance] implementation and always
/// throws an [UnsupportedError] when called. This behavior is consistent with
/// the purpose of [EmptyReflector], which provides non-functional placeholders
/// for reflection operations.
///
/// @param name The name of the field to retrieve.
/// @throws UnsupportedError Always thrown when this method is called.
/// @return This method never returns as it always throws an exception.
@override
ReflectedInstance getField(String name) {
throw UnsupportedError(
'Instances reflected via an EmptyReflector cannot call getField().');
}
}
/// An empty implementation of [ReflectedFunction] used by [EmptyReflector].
///
/// This class provides a non-functional placeholder for reflection operations
/// on functions. It is designed to be used in contexts where reflection capabilities
/// are expected but not actually needed or desired.
///
/// Key features:
/// - Extends [ReflectedFunction] with minimal implementation.
/// - Constructor initializes with empty or default values for all properties.
/// - [invoke] method throws an [UnsupportedError] if called.
///
/// This implementation is consistent with the purpose of [EmptyReflector],
/// providing a lightweight alternative when full reflection capabilities are not required.
class _EmptyReflectedFunction extends ReflectedFunction {
/// Constructs an empty [_EmptyReflectedFunction] instance.
///
/// This constructor initializes the instance with empty or default values for all properties.
///
/// @param name The name of the function, set to an empty string.
/// @param typeParameters A list of type parameters for the function, set to an empty list.
/// @param enclosingInstance A list of enclosing instances for the function, set to an empty list.
/// @param parameters A list of parameters for the function, set to an empty list.
/// @param isStatic Indicates whether the function is static, set to false.
/// @param isConst Indicates whether the function is constant, set to false.
/// @param returnType The return type of the function, set to an empty [_EmptyReflectedType].
/// @param isOperator Indicates whether the function is an operator, set to false.
/// @param isExtensionMember Indicates whether the function is an extension member, set to false.
const _EmptyReflectedFunction()
: super(
'(empty)',
const <ReflectedTypeParameter>[],
const <ReflectedInstance>[],
const <ReflectedParameter>[],
false,
false,
returnType: const _EmptyReflectedType());
/// Invokes this empty reflected function.
///
/// This method is part of the [_EmptyReflectedFunction] implementation and always
/// throws an [UnsupportedError] when called. This behavior is consistent with
/// the purpose of [EmptyReflector], which provides non-functional placeholders
/// for reflection operations.
///
/// @param invocation The invocation to execute.
/// @throws UnsupportedError Always thrown when this method is called.
/// @return This method never returns as it always throws an exception.
@override
ReflectedInstance invoke(Invocation invocation) {
throw UnsupportedError(
'Instances reflected via an EmptyReflector cannot call invoke().');
}
}

View file

@ -1,34 +0,0 @@
/*
* 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.
*/
/// A custom exception class for reflection-related errors.
///
/// This class extends the base [Exception] class and provides a way to
/// create exceptions specific to reflection operations. It includes a
/// message that describes the nature of the exception.
///
/// Example usage:
/// ```dart
/// throw ReflectionException('Failed to reflect on class XYZ');
/// ```
class ReflectionException implements Exception {
/// Creates a new instance of [ReflectionException] with the specified message.
///
/// The [message] parameter should describe the nature of the reflection error.
final String message;
/// Creates a new instance of [ReflectionException] with the specified message.
///
/// The [message] parameter should describe the nature of the reflection error.
ReflectionException(this.message);
// Override the toString method to provide a custom string representation of the exception.
@override
String toString() => message;
}

View file

@ -1,10 +0,0 @@
/*
* 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.
*/
export 'reflector.dart';

View file

@ -1,904 +0,0 @@
/*
* 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 'dart:async';
import 'dart:mirrors' as dart;
import 'package:platform_container/container.dart';
import 'package:quiver/core.dart';
/// A [Reflector] implementation that forwards to `dart:mirrors`.
///
/// This class provides reflection capabilities by leveraging the `dart:mirrors` library.
/// It allows for runtime introspection of classes, functions, types, and instances.
///
/// Key features:
/// - Reflects classes, functions, types, and instances
/// - Provides access to class and function metadata
/// - Supports reflection of generic types and futures
/// - Allows invocation of reflected functions
///
/// Note: This reflector is primarily useful on the server-side where reflection is fully supported.
/// It may not be suitable for client-side Dart applications due to limitations in reflection support.
///
/// Usage:
/// ```dart
/// final reflector = MirrorsReflector();
/// final classReflection = reflector.reflectClass(MyClass);
/// final functionReflection = reflector.reflectFunction(myFunction);
/// final typeReflection = reflector.reflectType(int);
/// final instanceReflection = reflector.reflectInstance(myObject);
/// ```
///
/// Be aware of the performance implications when using reflection extensively,
/// as it can impact runtime performance and increase code size.
class MirrorsReflector extends Reflector {
/// Creates a new instance of [MirrorsReflector].
///
/// This constructor initializes the [MirrorsReflector] instance.
const MirrorsReflector();
/// Retrieves the name of a symbol as a string.
///
/// This method overrides the base implementation to use the `dart:mirrors` library
/// for converting a [Symbol] to its corresponding string representation.
///
/// Parameters:
/// - [symbol]: The [Symbol] whose name is to be retrieved.
///
/// Returns:
/// A [String] representing the name of the given symbol.
///
/// Example:
/// ```dart
/// final name = getName(#someSymbol);
/// print(name); // Outputs: "someSymbol"
/// ```
@override
String getName(Symbol symbol) => dart.MirrorSystem.getName(symbol);
/// Reflects a class and returns a [ReflectedClass] instance.
///
/// This method takes a [Type] parameter [clazz] and uses dart:mirrors to create
/// a reflection of the class. It returns a [_ReflectedClassMirror] which
/// implements [ReflectedClass].
///
/// Parameters:
/// - [clazz]: The [Type] of the class to reflect.
///
/// Returns:
/// A [ReflectedClass] instance representing the reflected class.
///
/// Throws:
/// - [ArgumentError] if the provided [clazz] is not a class.
///
/// Example:
/// ```dart
/// final reflector = MirrorsReflector();
/// final classReflection = reflector.reflectClass(MyClass);
/// ```
@override
ReflectedClass reflectClass(Type clazz) {
var mirror = dart.reflectType(clazz);
if (mirror is dart.ClassMirror) {
return _ReflectedClassMirror(mirror);
} else {
throw ArgumentError('$clazz is not a class.');
}
}
/// Reflects a function and returns a [ReflectedFunction] instance.
///
/// This method takes a [Function] parameter [function] and uses dart:mirrors to create
/// a reflection of the function. It returns a [_ReflectedMethodMirror] which
/// implements [ReflectedFunction].
///
/// Parameters:
/// - [function]: The [Function] to reflect.
///
/// Returns:
/// A [ReflectedFunction] instance representing the reflected function.
///
/// Example:
/// ```dart
/// final reflector = MirrorsReflector();
/// final functionReflection = reflector.reflectFunction(myFunction);
/// ```
@override
ReflectedFunction reflectFunction(Function function) {
var closure = dart.reflect(function) as dart.ClosureMirror;
return _ReflectedMethodMirror(closure.function, closure);
}
/// Reflects a given type and returns a [ReflectedType] instance.
///
/// This method takes a [Type] parameter and uses dart:mirrors to create
/// a reflection of the type. It returns either a [_ReflectedClassMirror]
/// or a [_ReflectedTypeMirror] depending on whether the reflected type
/// is a class or not.
///
/// Parameters:
/// - [type]: The [Type] to reflect.
///
/// Returns:
/// A [ReflectedType] instance representing the reflected type.
///
/// If the reflected type doesn't have a reflected type (i.e., [hasReflectedType] is false),
/// it returns a reflection of the `dynamic` type instead.
///
/// Example:
/// ```dart
/// final reflector = MirrorsReflector();
/// final typeReflection = reflector.reflectType(int);
/// ```
@override
ReflectedType reflectType(Type type) {
var mirror = dart.reflectType(type);
if (!mirror.hasReflectedType) {
return reflectType(dynamic);
} else {
if (mirror is dart.ClassMirror) {
return _ReflectedClassMirror(mirror);
} else {
return _ReflectedTypeMirror(mirror);
}
}
}
/// Reflects a Future of a given type and returns a [ReflectedType] instance.
///
/// This method takes a [Type] parameter and creates a reflection of a Future
/// that wraps that type. It first reflects the inner type, then constructs
/// a Future type with that inner type as its type argument.
///
/// Parameters:
/// - [type]: The [Type] to be wrapped in a Future.
///
/// Returns:
/// A [ReflectedType] instance representing the reflected Future<Type>.
///
/// Throws:
/// - [ArgumentError] if the provided [type] is not a class or type.
///
/// Example:
/// ```dart
/// final reflector = MirrorsReflector();
/// final futureIntReflection = reflector.reflectFutureOf(int);
/// // This will reflect Future<int>
/// ```
@override
ReflectedType reflectFutureOf(Type type) {
var inner = reflectType(type);
dart.TypeMirror localMirror;
if (inner is _ReflectedClassMirror) {
localMirror = inner.mirror;
} else if (inner is _ReflectedTypeMirror) {
localMirror = inner.mirror;
} else {
throw ArgumentError('$type is not a class or type.');
}
var future = dart.reflectType(Future, [localMirror.reflectedType]);
return _ReflectedClassMirror(future as dart.ClassMirror);
}
/// Reflects an instance of an object and returns a [ReflectedInstance].
///
/// This method takes an [Object] parameter and uses dart:mirrors to create
/// a reflection of the object instance. It returns a [_ReflectedInstanceMirror]
/// which implements [ReflectedInstance].
///
/// Parameters:
/// - [object]: The object instance to reflect.
///
/// Returns:
/// A [ReflectedInstance] representing the reflected object instance.
///
/// Example:
/// ```dart
/// final reflector = MirrorsReflector();
/// final instanceReflection = reflector.reflectInstance(myObject);
/// ```
@override
ReflectedInstance reflectInstance(Object object) {
return _ReflectedInstanceMirror(dart.reflect(object));
}
}
/// Represents a reflected type parameter using dart:mirrors.
///
/// This class extends [ReflectedTypeParameter] and wraps a [dart.TypeVariableMirror]
/// to provide reflection capabilities for type parameters in Dart.
///
/// The class extracts the name of the type parameter from the mirror and passes
/// it to the superclass constructor.
///
/// This is typically used internally by the reflection system to represent
/// type parameters of generic classes or methods.
class _ReflectedTypeParameter extends ReflectedTypeParameter {
/// The [dart.TypeVariableMirror] instance representing the reflected type parameter.
///
/// This mirror provides access to the details of the type parameter, such as its name,
/// bounds, and other metadata. It is used internally by the [_ReflectedTypeParameter]
/// class to implement reflection capabilities for type parameters.
final dart.TypeVariableMirror mirror;
/// Constructs a [_ReflectedTypeParameter] instance.
///
/// This constructor takes a [dart.TypeVariableMirror] and initializes the
/// [_ReflectedTypeParameter] with the name of the type parameter extracted
/// from the mirror.
///
/// Parameters:
/// - [mirror]: A [dart.TypeVariableMirror] representing the type parameter.
///
/// The constructor uses [dart.MirrorSystem.getName] to extract the name of the
/// type parameter from the mirror's [simpleName] and passes it to the superclass
/// constructor.
_ReflectedTypeParameter(this.mirror)
: super(dart.MirrorSystem.getName(mirror.simpleName));
}
/// Represents a reflected type using dart:mirrors.
///
/// This class extends [ReflectedType] and wraps a [dart.TypeMirror]
/// to provide reflection capabilities for types in Dart.
///
/// The class extracts the name and type variables from the mirror and passes
/// them to the superclass constructor. It also implements type comparison
/// through the [isAssignableTo] method.
///
/// Note that this class represents types that are not classes, and therefore
/// cannot be instantiated. Attempting to call [newInstance] will throw a
/// [ReflectionException].
///
/// This is typically used internally by the reflection system to represent
/// non-class types like interfaces, mixins, or type aliases.
class _ReflectedTypeMirror extends ReflectedType {
/// The [dart.TypeMirror] instance representing the reflected type.
///
/// This mirror provides access to the details of the type, such as its name,
/// type variables, and other metadata. It is used internally by the
/// [_ReflectedTypeMirror] class to implement reflection capabilities for types.
final dart.TypeMirror mirror;
/// Constructs a [_ReflectedTypeMirror] instance.
///
/// This constructor takes a [dart.TypeMirror] and initializes the
/// [_ReflectedTypeMirror] with the following:
/// - The name of the type extracted from the mirror's [simpleName].
/// - A list of [_ReflectedTypeParameter] objects created from the mirror's type variables.
/// - The reflected type of the mirror.
///
/// Parameters:
/// - [mirror]: A [dart.TypeMirror] representing the type to be reflected.
///
/// The constructor uses [dart.MirrorSystem.getName] to extract the name of the
/// type from the mirror's [simpleName]. It also maps the mirror's type variables
/// to [_ReflectedTypeParameter] objects and passes them along with the reflected
/// type to the superclass constructor.
_ReflectedTypeMirror(this.mirror)
: super(
dart.MirrorSystem.getName(mirror.simpleName),
mirror.typeVariables.map((m) => _ReflectedTypeParameter(m)).toList(),
mirror.reflectedType,
);
/// Checks if this reflected class is assignable to another reflected type.
///
/// This method determines whether an instance of this class can be assigned
/// to a variable of the type represented by [other].
///
/// Parameters:
/// - [other]: The [ReflectedType] to check against.
///
/// Returns:
/// - `true` if this class is assignable to [other].
/// - `false` otherwise, including when [other] is not a [_ReflectedClassMirror]
/// or [_ReflectedTypeMirror].
///
/// The method uses dart:mirrors' [isAssignableTo] to perform the actual check
/// when [other] is either a [_ReflectedClassMirror] or [_ReflectedTypeMirror].
@override
bool isAssignableTo(ReflectedType? other) {
if (other is _ReflectedClassMirror) {
return mirror.isAssignableTo(other.mirror);
} else if (other is _ReflectedTypeMirror) {
return mirror.isAssignableTo(other.mirror);
} else {
return false;
}
}
/// Throws a [ReflectionException] when attempting to create a new instance.
///
/// This method is intended to be overridden by classes that represent
/// instantiable types. For non-instantiable types (like interfaces or
/// abstract classes), this method throws an exception.
///
/// Parameters:
/// - [constructorName]: The name of the constructor to invoke.
/// - [positionalArguments]: A list of positional arguments for the constructor.
/// - [namedArguments]: An optional map of named arguments for the constructor.
/// - [typeArguments]: An optional list of type arguments for generic classes.
///
/// Throws:
/// [ReflectionException]: Always thrown with a message indicating that
/// this type cannot be instantiated.
///
/// Example:
/// ```dart
/// // This will always throw a ReflectionException
/// reflectedType.newInstance('defaultConstructor', []);
/// ```
@override
ReflectedInstance newInstance(
String constructorName, List positionalArguments,
[Map<String, dynamic>? namedArguments, List<Type>? typeArguments]) {
throw ReflectionException(
'$name is not a class, and therefore cannot be instantiated.');
}
}
/// Represents a reflected class using dart:mirrors.
///
/// This class extends [ReflectedClass] and wraps a [dart.ClassMirror]
/// to provide reflection capabilities for Dart classes.
///
/// Key features:
/// - Reflects class name, type parameters, constructors, and declarations
/// - Provides access to class metadata (annotations)
/// - Supports type comparison through [isAssignableTo]
/// - Allows creation of new instances of the reflected class
///
/// This class is typically used internally by the reflection system to
/// represent classes and their members.
class _ReflectedClassMirror extends ReflectedClass {
/// The [dart.ClassMirror] representing the reflected class.
///
/// This mirror is used to extract information about the class, such as
/// its name, type parameters, constructors, and declarations.
///
/// See also:
/// - [dart.ClassMirror] for more details about the mirror system.
final dart.ClassMirror mirror;
/// Constructs a [_ReflectedClassMirror] instance.
///
/// This constructor takes a [dart.ClassMirror] and initializes the
/// [_ReflectedClassMirror] with the following:
/// - The name of the class extracted from the mirror's [simpleName].
/// - A list of [_ReflectedTypeParameter] objects created from the mirror's type variables.
/// - Empty lists for constructors and annotations (these are populated elsewhere).
/// - A list of declarations obtained from the [_declarationsOf] method.
/// - The reflected type of the mirror.
///
/// Parameters:
/// - [mirror]: A [dart.ClassMirror] representing the class to be reflected.
///
/// The constructor uses [dart.MirrorSystem.getName] to extract the name of the
/// class from the mirror's [simpleName]. It also maps the mirror's type variables
/// to [_ReflectedTypeParameter] objects and uses [_declarationsOf] to get the
/// class declarations. These are then passed to the superclass constructor.
_ReflectedClassMirror(this.mirror)
: super(
dart.MirrorSystem.getName(mirror.simpleName),
mirror.typeVariables.map((m) => _ReflectedTypeParameter(m)).toList(),
[],
[],
_declarationsOf(mirror),
mirror.reflectedType,
);
/// Retrieves a list of reflected constructors from a given [dart.ClassMirror].
///
/// This static method iterates through the declarations of the provided [mirror],
/// identifies the constructor methods, and creates [ReflectedFunction] instances
/// for each constructor found.
///
/// Parameters:
/// - [mirror]: A [dart.ClassMirror] representing the class to examine.
///
/// Returns:
/// A [List] of [ReflectedFunction] objects, each representing a constructor
/// of the class.
///
/// The method specifically looks for [dart.MethodMirror] instances that are
/// marked as constructors (i.e., [isConstructor] is true). Each identified
/// constructor is wrapped in a [_ReflectedMethodMirror] and added to the
/// returned list.
static List<ReflectedFunction> _constructorsOf(dart.ClassMirror mirror) {
var out = <ReflectedFunction>[];
for (var key in mirror.declarations.keys) {
var value = mirror.declarations[key];
if (value is dart.MethodMirror && value.isConstructor) {
out.add(_ReflectedMethodMirror(value));
}
}
return out;
}
/// Retrieves a list of reflected declarations from a given [dart.ClassMirror].
///
/// This static method iterates through the declarations of the provided [mirror],
/// identifies non-constructor methods, and creates [ReflectedDeclaration] instances
/// for each method found.
///
/// Parameters:
/// - [mirror]: A [dart.ClassMirror] representing the class to examine.
///
/// Returns:
/// A [List] of [ReflectedDeclaration] objects, each representing a non-constructor
/// method of the class.
///
/// The method specifically looks for [dart.MethodMirror] instances that are
/// not constructors (i.e., [isConstructor] is false). Each identified
/// method is wrapped in a [_ReflectedDeclarationMirror] and added to the
/// returned list.
static List<ReflectedDeclaration> _declarationsOf(dart.ClassMirror mirror) {
var out = <ReflectedDeclaration>[];
for (var key in mirror.declarations.keys) {
var value = mirror.declarations[key];
if (value is dart.MethodMirror && !value.isConstructor) {
out.add(
_ReflectedDeclarationMirror(dart.MirrorSystem.getName(key), value));
}
}
return out;
}
/// Retrieves the annotations (metadata) associated with this reflected class.
///
/// This getter method overrides the base implementation to provide access to
/// the class-level annotations using dart:mirrors. It maps each metadata mirror
/// to a [_ReflectedInstanceMirror] and returns them as a list.
///
/// Returns:
/// A [List] of [ReflectedInstance] objects, each representing an annotation
/// applied to this class.
///
/// Example:
/// ```dart
/// @MyAnnotation()
/// class MyClass {}
///
/// // Assuming we have a reflection of MyClass
/// final classReflection = reflector.reflectClass(MyClass);
/// final annotations = classReflection.annotations;
/// // annotations will contain a ReflectedInstance of MyAnnotation
/// ```
///
/// Note: This method relies on the [dart.ClassMirror]'s metadata property
/// and creates a new [_ReflectedInstanceMirror] for each annotation.
@override
List<ReflectedInstance> get annotations =>
mirror.metadata.map((m) => _ReflectedInstanceMirror(m)).toList();
/// Retrieves a list of reflected constructors for this class.
///
/// This getter method overrides the base implementation to provide access to
/// the constructors of the reflected class using dart:mirrors. It uses the
/// static [_constructorsOf] method to extract and wrap each constructor
/// in a [ReflectedFunction] object.
///
/// Returns:
/// A [List] of [ReflectedFunction] objects, each representing a constructor
/// of this class.
///
/// Example:
/// ```dart
/// final classReflection = reflector.reflectClass(MyClass);
/// final constructors = classReflection.constructors;
/// // constructors will contain ReflectedFunction objects for each
/// // constructor in MyClass
/// ```
///
/// Note: This method relies on the [dart.ClassMirror]'s declarations and
/// the [_constructorsOf] method to identify and create reflections of
/// the class constructors.
@override
List<ReflectedFunction> get constructors => _constructorsOf(mirror);
/// Checks if this reflected type is assignable to another reflected type.
///
/// This method determines whether an instance of this type can be assigned
/// to a variable of the type represented by [other].
///
/// Parameters:
/// - [other]: The [ReflectedType] to check against.
///
/// Returns:
/// - `true` if this type is assignable to [other].
/// - `false` otherwise, including when [other] is not a [_ReflectedClassMirror]
/// or [_ReflectedTypeMirror].
///
/// The method uses dart:mirrors' [isAssignableTo] to perform the actual check
/// when [other] is either a [_ReflectedClassMirror] or [_ReflectedTypeMirror].
@override
bool isAssignableTo(ReflectedType? other) {
if (other is _ReflectedClassMirror) {
return mirror.isAssignableTo(other.mirror);
} else if (other is _ReflectedTypeMirror) {
return mirror.isAssignableTo(other.mirror);
} else {
return false;
}
}
/// Creates a new instance of the reflected class.
///
/// This method instantiates a new object of the class represented by this
/// [_ReflectedClassMirror] using the specified constructor and arguments.
///
/// Parameters:
/// - [constructorName]: The name of the constructor to invoke. Use an empty
/// string for the default constructor.
/// - [positionalArguments]: A list of positional arguments to pass to the constructor.
/// - [namedArguments]: An optional map of named arguments to pass to the constructor.
/// - [typeArguments]: An optional list of type arguments for generic classes.
///
/// Returns:
/// A [ReflectedInstance] representing the newly created instance.
///
/// Throws:
/// May throw exceptions if the constructor invocation fails, e.g., due to
/// invalid arguments or if the class cannot be instantiated.
///
/// Note:
/// This implementation currently does not use the [namedArguments] or
/// [typeArguments] parameters. They are included for API compatibility.
@override
ReflectedInstance newInstance(
String constructorName, List positionalArguments,
[Map<String, dynamic>? namedArguments, List<Type>? typeArguments]) {
return _ReflectedInstanceMirror(
mirror.newInstance(Symbol(constructorName), positionalArguments));
}
/// Checks if this [_ReflectedClassMirror] is equal to another object.
///
/// This method overrides the default equality operator to provide a custom
/// equality check for [_ReflectedClassMirror] instances.
///
/// Parameters:
/// - [other]: The object to compare with this [_ReflectedClassMirror].
///
/// Returns:
/// - `true` if [other] is also a [_ReflectedClassMirror] and has the same
/// [mirror] as this instance.
/// - `false` otherwise.
///
/// This implementation ensures that two [_ReflectedClassMirror] instances
/// are considered equal if and only if they reflect the same class (i.e.,
/// their underlying [dart.ClassMirror]s are the same).
@override
bool operator ==(other) {
return other is _ReflectedClassMirror && other.mirror == mirror;
}
/// Generates a hash code for this [_ReflectedClassMirror].
///
/// This method overrides the default [hashCode] implementation to provide
/// a consistent hash code for [_ReflectedClassMirror] instances.
///
/// The hash code is generated using the [hash2] function from the Quiver
/// library, combining the [mirror] object and an empty string. The empty
/// string is used as a second parameter to maintain compatibility with
/// the [hash2] function, which requires two arguments.
///
/// Returns:
/// An [int] representing the hash code of this [_ReflectedClassMirror].
///
/// Note:
/// This hash code implementation ensures that two [_ReflectedClassMirror]
/// instances with the same [mirror] will have the same hash code, which
/// is consistent with the equality check implemented in the [operator ==].
@override
int get hashCode => hash2(mirror, " ");
}
/// Represents a reflected declaration using dart:mirrors.
///
/// This class extends [ReflectedDeclaration] and wraps a [dart.MethodMirror]
/// to provide reflection capabilities for method declarations in Dart.
///
/// Key features:
/// - Reflects the name and static nature of the declaration
/// - Provides access to the underlying method as a [ReflectedFunction]
///
/// This class is typically used internally by the reflection system to
/// represent method declarations within a class.
class _ReflectedDeclarationMirror extends ReflectedDeclaration {
/// The [dart.MethodMirror] instance representing the reflected method.
///
/// This mirror provides access to the details of the method, such as its name,
/// parameters, return type, and other metadata. It is used internally by the
/// [_ReflectedDeclarationMirror] class to implement reflection capabilities
/// for method declarations.
final dart.MethodMirror mirror;
/// Constructs a [_ReflectedDeclarationMirror] instance.
///
/// This constructor initializes a new [_ReflectedDeclarationMirror] with the given [name]
/// and [mirror]. It uses the [dart.MethodMirror]'s [isStatic] property to determine
/// if the declaration is static, and passes `null` as the initial value for the function.
///
/// Parameters:
/// - [name]: A [String] representing the name of the declaration.
/// - [mirror]: A [dart.MethodMirror] representing the reflected method.
///
/// The constructor calls the superclass constructor with the provided [name],
/// the [isStatic] property from the [mirror], and `null` for the function parameter.
_ReflectedDeclarationMirror(String name, this.mirror)
: super(name, mirror.isStatic, null);
/// Determines if this declaration is static.
///
/// This getter overrides the base implementation to provide information
/// about whether the reflected declaration is static or not. It directly
/// accesses the [isStatic] property of the underlying [dart.MethodMirror].
///
/// Returns:
/// A [bool] value:
/// - `true` if the declaration is static.
/// - `false` if the declaration is not static (i.e., it's an instance method).
///
/// This property is useful for determining the nature of the reflected
/// declaration, particularly when working with class methods and properties.
@override
bool get isStatic => mirror.isStatic;
/// Retrieves a [ReflectedFunction] representation of this declaration.
///
/// This getter overrides the base implementation to provide a [ReflectedFunction]
/// that represents the method associated with this declaration. It creates a new
/// [_ReflectedMethodMirror] instance using the underlying [dart.MethodMirror].
///
/// Returns:
/// A [ReflectedFunction] object that represents the method of this declaration.
///
/// This property is useful for accessing detailed information about the method,
/// such as its parameters, return type, and other attributes, in a way that's
/// consistent with the reflection API.
@override
ReflectedFunction get function => _ReflectedMethodMirror(mirror);
}
/// Represents a reflected instance of an object using dart:mirrors.
///
/// This class extends [ReflectedInstance] and wraps a [dart.InstanceMirror]
/// to provide reflection capabilities for object instances in Dart.
///
/// Key features:
/// - Reflects the type and runtime type of the instance
/// - Provides access to the underlying object (reflectee)
/// - Allows retrieval of field values through reflection
///
/// This class is typically used internally by the reflection system to
/// represent instances of objects and provide reflective access to their fields.
class _ReflectedInstanceMirror extends ReflectedInstance {
/// The [dart.InstanceMirror] representing the reflected instance.
///
/// This mirror provides access to the details of the object instance, such as its type,
/// fields, and methods. It is used internally by the [_ReflectedInstanceMirror] class
/// to implement reflection capabilities for object instances.
///
/// The mirror allows for dynamic inspection and manipulation of the object's state
/// and behavior at runtime, enabling powerful reflection features.
final dart.InstanceMirror mirror;
/// Constructs a [_ReflectedInstanceMirror] instance.
///
/// This constructor initializes a new [_ReflectedInstanceMirror] with the given [mirror].
/// It uses the [dart.InstanceMirror]'s [type] property to create [_ReflectedClassMirror]
/// instances for both the type and runtime type of the reflected instance.
///
/// Parameters:
/// - [mirror]: A [dart.InstanceMirror] representing the reflected instance.
///
/// The constructor calls the superclass constructor with:
/// - A [_ReflectedClassMirror] of the instance's type
/// - A [_ReflectedClassMirror] of the instance's runtime type
/// - The [reflectee] of the mirror, which is the actual object being reflected
///
/// This setup allows the [_ReflectedInstanceMirror] to provide access to both
/// the compile-time and runtime type information of the reflected instance,
/// as well as the underlying object itself.
_ReflectedInstanceMirror(this.mirror)
: super(_ReflectedClassMirror(mirror.type),
_ReflectedClassMirror(mirror.type), mirror.reflectee);
/// Retrieves the value of a field from the reflected instance.
///
/// This method allows access to field values of the object represented by this
/// [_ReflectedInstanceMirror] through reflection.
///
/// Parameters:
/// - [name]: A [String] representing the name of the field to retrieve.
///
/// Returns:
/// A [ReflectedInstance] representing the value of the specified field.
/// This returned instance is wrapped in a [_ReflectedInstanceMirror].
///
/// Throws:
/// May throw exceptions if the field does not exist or if access is not allowed.
///
/// Example:
/// ```dart
/// var fieldValue = reflectedInstance.getField('myField');
/// ```
///
/// Note:
/// This method uses the underlying [dart.InstanceMirror]'s [getField] method
/// to perform the actual field access.
@override
ReflectedInstance getField(String name) {
return _ReflectedInstanceMirror(mirror.getField(Symbol(name)));
}
}
/// Represents a reflected method using dart:mirrors.
///
/// This class extends [ReflectedFunction] and wraps a [dart.MethodMirror]
/// to provide reflection capabilities for methods in Dart.
///
/// Key features:
/// - Reflects method name, parameters, and return type
/// - Provides access to method metadata (annotations)
/// - Supports invocation of the reflected method (if a ClosureMirror is available)
///
/// The class uses both [dart.MethodMirror] and optionally [dart.ClosureMirror]
/// to represent and potentially invoke the reflected method.
///
/// Usage:
/// - Created internally by the reflection system to represent methods
/// - Can be used to inspect method details or invoke the method if a ClosureMirror is provided
///
/// Note:
/// - Invocation is only possible if a ClosureMirror is provided during construction
/// - Throws a StateError if invoke is called without a ClosureMirror
class _ReflectedMethodMirror extends ReflectedFunction {
/// The [dart.MethodMirror] instance representing the reflected method.
///
/// This mirror provides access to the details of the method, such as its name,
/// parameters, return type, and other metadata. It is used internally by the
/// [_ReflectedMethodMirror] class to implement reflection capabilities
/// for methods.
///
/// The [dart.MethodMirror] is a crucial component in the reflection process,
/// allowing for introspection of method properties and behavior at runtime.
final dart.MethodMirror mirror;
/// An optional [dart.ClosureMirror] representing the closure of the reflected method.
///
/// This field is used to store a [dart.ClosureMirror] when the reflected method
/// is associated with a callable object (i.e., a closure). The presence of this
/// mirror enables the [invoke] method to directly call the reflected method.
///
/// If this field is null, it indicates that the reflected method cannot be
/// directly invoked through this [_ReflectedMethodMirror] instance.
///
/// Note:
/// - This field is crucial for supporting method invocation via reflection.
/// - It's typically set when reflecting on instance methods or standalone functions.
/// - For class-level method declarations that aren't bound to an instance,
/// this field may be null.
final dart.ClosureMirror? closureMirror;
/// Constructs a [_ReflectedMethodMirror] instance.
///
/// This constructor initializes a new [_ReflectedMethodMirror] with the given [mirror]
/// and optional [closureMirror]. It extracts various properties from the [dart.MethodMirror]
/// to populate the superclass constructor.
///
/// Parameters:
/// - [mirror]: A [dart.MethodMirror] representing the reflected method.
/// - [closureMirror]: An optional [dart.ClosureMirror] for method invocation.
///
/// The constructor initializes the following:
/// - Method name from the mirror's [simpleName]
/// - An empty list of reflected type parameters
/// - Metadata (annotations) as [_ReflectedInstanceMirror] objects
/// - Reflected parameters using [_reflectParameter]
/// - Getter and setter flags from the mirror
/// - Return type, using [dynamic] if the mirror doesn't have a reflected type
///
/// This setup allows the [_ReflectedMethodMirror] to provide comprehensive
/// reflection capabilities for the method, including its signature, metadata,
/// and potential invocation (if a [closureMirror] is provided).
_ReflectedMethodMirror(this.mirror, [this.closureMirror])
: super(
dart.MirrorSystem.getName(mirror.simpleName),
<ReflectedTypeParameter>[],
mirror.metadata
.map((mirror) => _ReflectedInstanceMirror(mirror))
.toList(),
mirror.parameters.map(_reflectParameter).toList(),
mirror.isGetter,
mirror.isSetter,
returnType: !mirror.returnType.hasReflectedType
? const MirrorsReflector().reflectType(dynamic)
: const MirrorsReflector()
.reflectType(mirror.returnType.reflectedType));
/// Reflects a parameter of a method using dart:mirrors.
///
/// This static method creates a [ReflectedParameter] instance from a given [dart.ParameterMirror].
/// It extracts various properties from the mirror to construct a comprehensive reflection of the parameter.
///
/// Parameters:
/// - [mirror]: A [dart.ParameterMirror] representing the parameter to be reflected.
///
/// Returns:
/// A [ReflectedParameter] instance containing the reflected information of the parameter.
///
/// The method extracts the following information:
/// - Parameter name from the mirror's [simpleName]
/// - Metadata (annotations) as [_ReflectedInstanceMirror] objects
/// - Parameter type, reflected using [MirrorsReflector]
/// - Whether the parameter is required (not optional)
/// - Whether the parameter is named
///
/// This method is typically used internally by the reflection system to create
/// parameter reflections for method signatures.
static ReflectedParameter _reflectParameter(dart.ParameterMirror mirror) {
return ReflectedParameter(
dart.MirrorSystem.getName(mirror.simpleName),
mirror.metadata
.map((mirror) => _ReflectedInstanceMirror(mirror))
.toList(),
const MirrorsReflector().reflectType(mirror.type.reflectedType),
!mirror.isOptional,
mirror.isNamed);
}
/// Invokes the reflected method with the given invocation details.
///
/// This method allows for dynamic invocation of the reflected method using the
/// provided [Invocation] object. It requires that a [closureMirror] was provided
/// during the construction of this [_ReflectedMethodMirror].
///
/// Parameters:
/// - [invocation]: An [Invocation] object containing the details of the method call,
/// including the method name, positional arguments, and named arguments.
///
/// Returns:
/// A [ReflectedInstance] representing the result of the method invocation.
///
/// Throws:
/// - [StateError] if this [_ReflectedMethodMirror] was created without a [closureMirror],
/// indicating that direct invocation is not possible.
///
/// Example:
/// ```dart
/// var result = reflectedMethod.invoke(Invocation.method(#methodName, [arg1, arg2]));
/// ```
///
/// Note:
/// This method relies on the presence of a [closureMirror] to perform the actual
/// invocation. If no [closureMirror] is available, it means the reflected method
/// cannot be directly invoked, and an error will be thrown.
@override
ReflectedInstance invoke(Invocation invocation) {
if (closureMirror == null) {
throw StateError(
'This object was reflected without a ClosureMirror, and therefore cannot be directly invoked.');
}
return _ReflectedInstanceMirror(closureMirror!.invoke(invocation.memberName,
invocation.positionalArguments, invocation.namedArguments));
}
}

View file

@ -1,8 +0,0 @@
/*
* 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.
*/

View file

@ -1,298 +0,0 @@
/*
* 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 'package:collection/collection.dart';
import 'package:quiver/core.dart';
/// Abstract class representing a reflector for introspection of Dart types and instances.
///
/// This class provides methods to reflect on various Dart constructs such as classes,
/// functions, types, and instances. It allows for runtime inspection and manipulation
/// of code elements.
///
/// The methods in this class are designed to be implemented by concrete reflector
/// classes, potentially using different reflection mechanisms (e.g., mirrors, code
/// generation).
///
/// Note: The `reflectFutureOf` method throws an `UnsupportedError` by default and
/// requires `dart:mirrors` for implementation.
abstract class Reflector {
/// Constructs a new [Reflector] instance.
///
/// This constructor is declared as `const` to allow for compile-time constant creation
/// of [Reflector] instances. Subclasses of [Reflector] may override this constructor
/// to provide their own initialization logic if needed.
const Reflector();
String? getName(Symbol symbol);
ReflectedClass? reflectClass(Type clazz);
ReflectedFunction? reflectFunction(Function function);
ReflectedType? reflectType(Type type);
ReflectedInstance? reflectInstance(Object object);
ReflectedType reflectFutureOf(Type type) {
throw UnsupportedError('`reflectFutureOf` requires `dart:mirrors`.');
}
}
/// Represents a reflected instance of an object.
///
/// This abstract class provides a way to introspect and manipulate object instances
/// at runtime. It encapsulates information about the object's type, class, and the
/// actual object instance (reflectee).
///
/// The [type] property represents the reflected type of the instance.
/// The [clazz] property represents the reflected class of the instance.
/// The [reflectee] property holds the actual object instance being reflected.
///
/// This class also provides methods for comparing instances and accessing fields.
///
/// Use the [getField] method to retrieve a reflected instance of a specific field.
abstract class ReflectedInstance {
final ReflectedType type;
final ReflectedClass clazz;
final Object? reflectee;
const ReflectedInstance(this.type, this.clazz, this.reflectee);
@override
int get hashCode => hash2(type, clazz);
@override
bool operator ==(other) =>
other is ReflectedInstance && other.type == type && other.clazz == clazz;
ReflectedInstance getField(String name);
}
/// Represents a reflected type in the Dart language.
///
/// This abstract class encapsulates information about a Dart type, including its name,
/// type parameters, and the actual Dart [Type] it represents.
///
/// The [name] property holds the name of the type.
/// The [typeParameters] list contains the type parameters if the type is generic.
/// The [reflectedType] property holds the actual Dart [Type] being reflected.
///
/// This class provides methods for creating new instances of the type, comparing types,
/// and checking type assignability.
///
/// The [newInstance] method allows for dynamic creation of new instances of the type.
/// The [isAssignableTo] method checks if this type is assignable to another type.
///
/// This class also overrides [hashCode] and [operator ==] for proper equality comparisons.
abstract class ReflectedType {
final String name;
final List<ReflectedTypeParameter> typeParameters;
final Type reflectedType;
const ReflectedType(this.name, this.typeParameters, this.reflectedType);
@override
int get hashCode => hash3(name, typeParameters, reflectedType);
@override
bool operator ==(other) =>
other is ReflectedType &&
other.name == name &&
const ListEquality<ReflectedTypeParameter>()
.equals(other.typeParameters, typeParameters) &&
other.reflectedType == reflectedType;
ReflectedInstance newInstance(
String constructorName, List positionalArguments,
[Map<String, dynamic> namedArguments = const {},
List<Type> typeArguments = const []]);
bool isAssignableTo(ReflectedType? other);
}
/// Represents a reflected class in the Dart language.
///
/// This abstract class extends [ReflectedType] and provides additional information
/// specific to classes, including annotations, constructors, and declarations.
///
/// The [annotations] list contains reflected instances of annotations applied to the class.
/// The [constructors] list contains reflected functions representing the class constructors.
/// The [declarations] list contains reflected declarations (fields, methods, etc.) of the class.
///
/// This class overrides [hashCode] and [operator ==] to include the additional properties
/// in equality comparisons and hash code calculations.
abstract class ReflectedClass extends ReflectedType {
final List<ReflectedInstance> annotations;
final List<ReflectedFunction> constructors;
final List<ReflectedDeclaration> declarations;
const ReflectedClass(
String name,
List<ReflectedTypeParameter> typeParameters,
this.annotations,
this.constructors,
this.declarations,
Type reflectedType)
: super(name, typeParameters, reflectedType);
@override
int get hashCode =>
hash4(super.hashCode, annotations, constructors, declarations);
@override
bool operator ==(other) =>
other is ReflectedClass &&
super == other &&
const ListEquality<ReflectedInstance>()
.equals(other.annotations, annotations) &&
const ListEquality<ReflectedFunction>()
.equals(other.constructors, constructors) &&
const ListEquality<ReflectedDeclaration>()
.equals(other.declarations, declarations);
}
/// Represents a reflected declaration in the Dart language.
///
/// This class encapsulates information about a declaration within a class or object,
/// such as a method, field, or property.
///
/// The [name] property holds the name of the declaration.
/// The [isStatic] property indicates whether the declaration is static.
/// The [function] property, if non-null, represents the reflected function associated
/// with this declaration (applicable for methods and some properties).
///
/// This class provides methods for comparing declarations and calculating hash codes.
/// It overrides [hashCode] and [operator ==] for proper equality comparisons.
class ReflectedDeclaration {
final String name;
final bool isStatic;
final ReflectedFunction? function;
const ReflectedDeclaration(this.name, this.isStatic, this.function);
@override
int get hashCode => hash3(name, isStatic, function);
@override
bool operator ==(other) =>
other is ReflectedDeclaration &&
other.name == name &&
other.isStatic == isStatic &&
other.function == function;
}
/// Represents a reflected function in the Dart language.
///
/// This abstract class encapsulates information about a function, including its name,
/// type parameters, annotations, return type, parameters, and whether it's a getter or setter.
///
/// The [name] property holds the name of the function.
/// The [typeParameters] list contains the type parameters if the function is generic.
/// The [annotations] list contains reflected instances of annotations applied to the function.
/// The [returnType] property represents the function's return type (if applicable).
/// The [parameters] list contains the function's parameters.
/// The [isGetter] and [isSetter] properties indicate if the function is a getter or setter.
///
/// This class provides methods for comparing functions and calculating hash codes.
/// It also includes an [invoke] method for dynamically calling the function.
///
/// This class overrides [hashCode] and [operator ==] for proper equality comparisons.
abstract class ReflectedFunction {
final String name;
final List<ReflectedTypeParameter> typeParameters;
final List<ReflectedInstance> annotations;
final ReflectedType? returnType;
final List<ReflectedParameter> parameters;
final bool isGetter, isSetter;
const ReflectedFunction(this.name, this.typeParameters, this.annotations,
this.parameters, this.isGetter, this.isSetter,
{this.returnType});
@override
int get hashCode => hashObjects([
name,
typeParameters,
annotations,
returnType,
parameters,
isGetter,
isSetter
]);
@override
bool operator ==(other) =>
other is ReflectedFunction &&
other.name == name &&
const ListEquality<ReflectedTypeParameter>()
.equals(other.typeParameters, typeParameters) &&
const ListEquality<ReflectedInstance>()
.equals(other.annotations, annotations) &&
other.returnType == returnType &&
const ListEquality<ReflectedParameter>()
.equals(other.parameters, other.parameters) &&
other.isGetter == isGetter &&
other.isSetter == isSetter;
ReflectedInstance invoke(Invocation invocation);
}
/// Represents a reflected parameter in the Dart language.
///
/// This class encapsulates information about a function or method parameter,
/// including its name, annotations, type, and properties such as whether it's
/// required or named.
///
/// Properties:
/// - [name]: The name of the parameter.
/// - [annotations]: A list of reflected instances of annotations applied to the parameter.
/// - [type]: The reflected type of the parameter.
/// - [isRequired]: Indicates whether the parameter is required.
/// - [isNamed]: Indicates whether the parameter is a named parameter.
///
/// This class provides methods for comparing parameters and calculating hash codes.
/// It overrides [hashCode] and [operator ==] for proper equality comparisons.
class ReflectedParameter {
final String name;
final List<ReflectedInstance> annotations;
final ReflectedType type;
final bool isRequired;
final bool isNamed;
const ReflectedParameter(
this.name, this.annotations, this.type, this.isRequired, this.isNamed);
@override
int get hashCode =>
hashObjects([name, annotations, type, isRequired, isNamed]);
@override
bool operator ==(other) =>
other is ReflectedParameter &&
other.name == name &&
const ListEquality<ReflectedInstance>()
.equals(other.annotations, annotations) &&
other.type == type &&
other.isRequired == isRequired &&
other.isNamed == isNamed;
}
class ReflectedTypeParameter {
final String name;
const ReflectedTypeParameter(this.name);
@override
int get hashCode => hashObjects([name]);
@override
bool operator ==(other) =>
other is ReflectedTypeParameter && other.name == name;
}

View file

@ -1,179 +0,0 @@
/*
* 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 'package:platform_container/container.dart';
/// A static implementation of the [Reflector] class that performs simple [Map] lookups.
///
/// `package:platform_container_generator` uses this to create reflectors from analysis metadata.
class StaticReflector extends Reflector {
/// A map that associates [Symbol] objects with their corresponding string names.
///
/// This map is used to store and retrieve the string representations of symbols,
/// which can be useful for reflection and debugging purposes.
final Map<Symbol, String> names;
/// A map that associates [Type] objects with their corresponding [ReflectedType] objects.
///
/// This map is used to store and retrieve reflection information for different types,
/// allowing for runtime introspection of type metadata and structure.
final Map<Type, ReflectedType> types;
/// A map that associates [Function] objects with their corresponding [ReflectedFunction] objects.
///
/// This map is used to store and retrieve reflection information for functions,
/// enabling runtime introspection of function metadata, parameters, and return types.
final Map<Function, ReflectedFunction> functions;
/// A map that associates [Object] instances with their corresponding [ReflectedInstance] objects.
///
/// This map is used to store and retrieve reflection information for specific object instances,
/// allowing for runtime introspection of object properties, methods, and metadata.
final Map<Object, ReflectedInstance> instances;
/// Creates a new [StaticReflector] instance with optional parameters.
///
/// The [StaticReflector] constructor allows you to initialize the reflector
/// with pre-populated maps for names, types, functions, and instances.
///
/// Parameters:
/// - [names]: A map of [Symbol] to [String] for symbol name lookups. Defaults to an empty map.
/// - [types]: A map of [Type] to [ReflectedType] for type reflection. Defaults to an empty map.
/// - [functions]: A map of [Function] to [ReflectedFunction] for function reflection. Defaults to an empty map.
/// - [instances]: A map of [Object] to [ReflectedInstance] for instance reflection. Defaults to an empty map.
///
/// All parameters are optional and default to empty constant maps if not provided.
const StaticReflector(
{this.names = const {},
this.types = const {},
this.functions = const {},
this.instances = const {}});
/// Returns the string name associated with the given [Symbol].
///
/// This method looks up the string representation of the provided [symbol]
/// in the [names] map. If the symbol is found, its corresponding string
/// name is returned. If the symbol is not found in the map, an [ArgumentError]
/// is thrown.
///
/// Parameters:
/// - [symbol]: The [Symbol] for which to retrieve the string name.
///
/// Returns:
/// The string name associated with the given [symbol], or null if not found.
///
/// Throws:
/// - [ArgumentError]: If the provided [symbol] is not found in the [names] map.
@override
String? getName(Symbol symbol) {
if (!names.containsKey(symbol)) {
throw ArgumentError(
'The value of $symbol is unknown - it was not generated.');
}
return names[symbol];
}
/// Reflects a class based on its [Type].
///
/// This method attempts to reflect the given class [Type] by calling [reflectType]
/// and casting the result to [ReflectedClass]. If the reflection is successful
/// and the result is a [ReflectedClass], it is returned. Otherwise, null is returned.
///
/// Parameters:
/// - [clazz]: The [Type] of the class to reflect.
///
/// Returns:
/// A [ReflectedClass] instance if the reflection is successful and the result
/// is a [ReflectedClass], or null otherwise.
@override
ReflectedClass? reflectClass(Type clazz) =>
reflectType(clazz) as ReflectedClass?;
/// Reflects a function based on its [Function] object.
///
/// This method attempts to retrieve reflection information for the given [function]
/// from the [functions] map. If the function is found in the map, its corresponding
/// [ReflectedFunction] object is returned. If the function is not found, an
/// [ArgumentError] is thrown.
///
/// Parameters:
/// - [function]: The [Function] object to reflect.
///
/// Returns:
/// A [ReflectedFunction] object containing reflection information about the
/// given function, or null if not found.
///
/// Throws:
/// - [ArgumentError]: If there is no reflection information available for
/// the given [function].
@override
ReflectedFunction? reflectFunction(Function function) {
if (!functions.containsKey(function)) {
throw ArgumentError(
'There is no reflection information available about $function.');
}
return functions[function];
}
/// Reflects an object instance to retrieve its reflection information.
///
/// This method attempts to retrieve reflection information for the given [object]
/// from the [instances] map. If the object is found in the map, its corresponding
/// [ReflectedInstance] object is returned. If the object is not found, an
/// [ArgumentError] is thrown.
///
/// Parameters:
/// - [object]: The object instance to reflect.
///
/// Returns:
/// A [ReflectedInstance] object containing reflection information about the
/// given object instance, or null if not found.
///
/// Throws:
/// - [ArgumentError]: If there is no reflection information available for
/// the given [object].
@override
ReflectedInstance? reflectInstance(Object object) {
if (!instances.containsKey(object)) {
throw ArgumentError(
'There is no reflection information available about $object.');
}
return instances[object];
}
/// Reflects a type to retrieve its reflection information.
///
/// This method attempts to retrieve reflection information for the given [type]
/// from the [types] map. If the type is found in the map, its corresponding
/// [ReflectedType] object is returned. If the type is not found, an
/// [ArgumentError] is thrown.
///
/// Parameters:
/// - [type]: The [Type] to reflect.
///
/// Returns:
/// A [ReflectedType] object containing reflection information about the
/// given type, or null if not found.
///
/// Throws:
/// - [ArgumentError]: If there is no reflection information available for
/// the given [type].
@override
ReflectedType? reflectType(Type type) {
if (!types.containsKey(type)) {
throw ArgumentError(
'There is no reflection information available about $type.');
}
return types[type];
}
}

View file

@ -1,93 +0,0 @@
import 'package:platform_container/src/container_const.dart';
import 'empty/empty.dart';
import 'reflector.dart';
/// A [Reflector] implementation that throws exceptions on all attempts
/// to perform reflection.
///
/// Use this in contexts where you know you won't need any reflective capabilities.
class ThrowingReflector extends Reflector {
/// The error message to give the end user when an [UnsupportedError] is thrown.
final String errorMessage;
/*
static const String defaultErrorMessage =
'You attempted to perform a reflective action, but you are using `ThrowingReflector`, '
'a class which disables reflection. Consider using the `MirrorsReflector` '
'class if you need reflection.';
*/
/// Creates a [ThrowingReflector] instance.
///
/// [errorMessage] is the message to be used when throwing an [UnsupportedError].
/// If not provided, it defaults to [ContainerConst.defaultErrorMessage].
const ThrowingReflector(
{this.errorMessage = ContainerConst.defaultErrorMessage});
/// Retrieves the name associated with the given [symbol].
///
/// This method delegates the task to an instance of [EmptyReflector].
/// It returns the name as a [String] if found, or `null` if not found.
///
/// [symbol] is the [Symbol] for which to retrieve the name.
///
/// Returns a [String] representing the name of the symbol, or `null` if not found.
@override
String? getName(Symbol symbol) => const EmptyReflector().getName(symbol);
/// Creates and returns an [UnsupportedError] with the specified [errorMessage].
///
/// This method is used internally to generate consistent error messages
/// when reflection operations are attempted on this [ThrowingReflector].
///
/// Returns an [UnsupportedError] instance with the configured error message.
UnsupportedError _error() => UnsupportedError(errorMessage);
/// Reflects on a given class type and throws an [UnsupportedError].
///
/// This method is part of the [ThrowingReflector] implementation and is designed
/// to prevent reflective operations. When called, it throws an [UnsupportedError]
/// with the configured error message.
///
/// [clazz] is the [Type] of the class to reflect on.
///
/// Throws an [UnsupportedError] when invoked, as reflection is not supported.
@override
ReflectedClass reflectClass(Type clazz) => throw _error();
/// Reflects on a given object instance and throws an [UnsupportedError].
///
/// This method is part of the [ThrowingReflector] implementation and is designed
/// to prevent reflective operations on object instances. When called, it throws
/// an [UnsupportedError] with the configured error message.
///
/// [object] is the object instance to reflect on.
///
/// Throws an [UnsupportedError] when invoked, as reflection is not supported.
@override
ReflectedInstance reflectInstance(Object object) => throw _error();
/// Reflects on a given type and throws an [UnsupportedError].
///
/// This method is part of the [ThrowingReflector] implementation and is designed
/// to prevent reflective operations on types. When called, it throws an
/// [UnsupportedError] with the configured error message.
///
/// [type] is the [Type] to reflect on.
///
/// Throws an [UnsupportedError] when invoked, as reflection is not supported.
@override
ReflectedType reflectType(Type type) => throw _error();
/// Reflects on a given function and throws an [UnsupportedError].
///
/// This method is part of the [ThrowingReflector] implementation and is designed
/// to prevent reflective operations on functions. When called, it throws an
/// [UnsupportedError] with the configured error message.
///
/// [function] is the [Function] to reflect on.
///
/// Throws an [UnsupportedError] when invoked, as reflection is not supported.
@override
ReflectedFunction reflectFunction(Function function) => throw _error();
}

View file

@ -1,14 +0,0 @@
name: platform_container
version: 9.0.0
description: Protevus Platform hierarchical DI container, and pluggable backends for reflection.
homepage: https://protevus.com
documentation: https://docs.protevus.com
repository: https://git.protevus.com/protevus/platform/src/branch/main/packages/container/container
environment:
sdk: '>=3.3.0 <4.0.0'
dependencies:
collection: ^1.19.1
quiver: ^3.2.2
dev_dependencies:
test: ^1.25.8
lints: ^4.0.0

View file

@ -1,122 +0,0 @@
import 'dart:async';
import 'package:platform_container/container.dart';
import 'package:test/test.dart';
void returnVoidFromAFunction(int x) {}
void testReflector(Reflector reflector) {
var blaziken = Pokemon('Blaziken', PokemonType.fire);
late Container container;
setUp(() {
container = Container(reflector);
container.registerSingleton(blaziken);
container.registerFactory<Future<int>>((_) async => 46);
});
test('get field', () {
var blazikenMirror = reflector.reflectInstance(blaziken)!;
expect(blazikenMirror.getField('type').reflectee, blaziken.type);
});
group('reflectFunction', () {
var mirror = reflector.reflectFunction(returnVoidFromAFunction);
test('void return type returns dynamic', () {
expect(mirror!.returnType, reflector.reflectType(dynamic));
});
test('counts parameters', () {
expect(mirror!.parameters, hasLength(1));
});
test('counts types parameters', () {
expect(mirror!.typeParameters, isEmpty);
});
test('correctly reflects parameter types', () {
var p = mirror!.parameters[0];
expect(p.name, 'x');
expect(p.isRequired, true);
expect(p.isNamed, false);
expect(p.annotations, isEmpty);
expect(p.type, reflector.reflectType(int));
});
});
test('make on singleton type returns singleton', () {
expect(container.make(Pokemon), blaziken);
});
test('make with generic returns same as make with explicit type', () {
expect(container.make<Pokemon>(), blaziken);
});
test('make async returns async object', () async {
expect(container.makeAsync<int>(), completion(46));
});
test('make async returns sync object', () async {
expect(container.makeAsync<Pokemon>(), completion(blaziken));
});
test('make on aliased singleton returns singleton', () {
container.registerSingleton(blaziken, as: StateError);
expect(container.make(StateError), blaziken);
});
test('constructor injects singleton', () {
var lower = container.make<LowerPokemon>();
expect(lower.lowercaseName, blaziken.name.toLowerCase());
});
test('newInstance works', () {
var type = container.reflector.reflectType(Pokemon)!;
var instance =
type.newInstance('changeName', [blaziken, 'Charizard']).reflectee
as Pokemon;
print(instance);
expect(instance.name, 'Charizard');
expect(instance.type, PokemonType.fire);
});
test('isAssignableTo', () {
var pokemonType = container.reflector.reflectType(Pokemon);
var kantoPokemonType = container.reflector.reflectType(KantoPokemon)!;
expect(kantoPokemonType.isAssignableTo(pokemonType), true);
expect(
kantoPokemonType
.isAssignableTo(container.reflector.reflectType(String)),
false);
});
}
class LowerPokemon {
final Pokemon pokemon;
LowerPokemon(this.pokemon);
String get lowercaseName => pokemon.name.toLowerCase();
}
class Pokemon {
final String name;
final PokemonType type;
Pokemon(this.name, this.type);
factory Pokemon.changeName(Pokemon other, String name) {
return Pokemon(name, other.type);
}
@override
String toString() => 'NAME: $name, TYPE: $type';
}
class KantoPokemon extends Pokemon {
KantoPokemon(super.name, super.type);
}
enum PokemonType { water, fire, grass, ice, poison, flying }

View file

@ -1,138 +0,0 @@
import 'package:platform_container/container.dart';
import 'package:test/test.dart';
void main() {
var reflector = const EmptyReflector();
test('getName', () {
expect(reflector.getName(#foo), 'foo');
expect(reflector.getName(#==), '==');
});
group('reflectClass', () {
var mirror = reflector.reflectClass(Truck);
test('name returns empty', () {
expect(mirror.name, '(empty)');
});
test('annotations returns empty', () {
expect(mirror.annotations, isEmpty);
});
test('typeParameters returns empty', () {
expect(mirror.typeParameters, isEmpty);
});
test('declarations returns empty', () {
expect(mirror.declarations, isEmpty);
});
test('constructors returns empty', () {
expect(mirror.constructors, isEmpty);
});
test('reflectedType returns Object', () {
expect(mirror.reflectedType, Object);
});
test('cannot call newInstance', () {
expect(() => mirror.newInstance('', []), throwsUnsupportedError);
});
test('isAssignableTo self', () {
expect(mirror.isAssignableTo(mirror), true);
});
});
group('reflectType', () {
var mirror = reflector.reflectType(Truck);
test('name returns empty', () {
expect(mirror.name, '(empty)');
});
test('typeParameters returns empty', () {
expect(mirror.typeParameters, isEmpty);
});
test('reflectedType returns Object', () {
expect(mirror.reflectedType, Object);
});
test('cannot call newInstance', () {
expect(() => mirror.newInstance('', []), throwsUnsupportedError);
});
test('isAssignableTo self', () {
expect(mirror.isAssignableTo(mirror), true);
});
});
group('reflectFunction', () {
void doIt(int x) {}
var mirror = reflector.reflectFunction(doIt);
test('name returns empty', () {
expect(mirror.name, '(empty)');
});
test('annotations returns empty', () {
expect(mirror.annotations, isEmpty);
});
test('typeParameters returns empty', () {
expect(mirror.typeParameters, isEmpty);
});
test('parameters returns empty', () {
expect(mirror.parameters, isEmpty);
});
test('return type is dynamic', () {
expect(mirror.returnType, reflector.reflectType(dynamic));
});
test('isGetter returns false', () {
expect(mirror.isGetter, false);
});
test('isSetter returns false', () {
expect(mirror.isSetter, false);
});
test('cannot invoke', () {
var invocation = Invocation.method(#drive, []);
expect(() => mirror.invoke(invocation), throwsUnsupportedError);
});
});
group('reflectInstance', () {
var mirror = reflector.reflectInstance(Truck());
test('reflectee returns null', () {
expect(mirror.reflectee, null);
});
test('type returns empty', () {
expect(mirror.type.name, '(empty)');
});
test('clazz returns empty', () {
expect(mirror.clazz.name, '(empty)');
});
test('cannot getField', () {
expect(() => mirror.getField('wheelCount'), throwsUnsupportedError);
});
});
}
class Truck {
int get wheelCount => 4;
void drive() {
print('Vroom!!!');
}
}

View file

@ -1,51 +0,0 @@
import 'package:platform_container/container.dart';
import 'package:test/test.dart';
void main() {
late Container container;
setUp(() {
container = Container(const EmptyReflector())
..registerSingleton<Song>(Song(title: 'I Wish'))
..registerNamedSingleton('foo', 1)
..registerFactory<Artist>((container) {
return Artist(
name: 'Stevie Wonder',
song: container.make<Song>(),
);
});
});
test('hasNamed', () {
var child = container.createChild()..registerNamedSingleton('bar', 2);
expect(child.hasNamed('foo'), true);
expect(child.hasNamed('bar'), true);
expect(child.hasNamed('baz'), false);
});
test('has on singleton', () {
var result = container.has<Song>();
expect(result, true);
});
test('has on factory', () {
expect(container.has<Artist>(), true);
});
test('false if neither', () {
expect(container.has<bool>(), false);
});
}
class Artist {
final String? name;
final Song? song;
Artist({this.name, this.song});
}
class Song {
final String? title;
Song({this.title});
}

View file

@ -1,18 +0,0 @@
import 'package:platform_container/container.dart';
import 'package:test/test.dart';
void main() {
test('returns the same instance', () {
var container = Container(const EmptyReflector())
..registerLazySingleton<Dummy>((_) => Dummy('a'));
var first = container.make<Dummy>();
expect(container.make<Dummy>(), first);
});
}
class Dummy {
final String s;
Dummy(this.s);
}

Some files were not shown because too many files have changed in this diff Show more