add(angel3): adding re-branded angel3 container package

This commit is contained in:
Patrick Stewart 2024-09-22 18:43:11 -07:00
parent 1b2983d02b
commit be65590d2e
39 changed files with 16346 additions and 0 deletions

71
packages/container/container/.gitignore vendored Normal file
View file

@ -0,0 +1,71 @@
# 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

@ -0,0 +1,12 @@
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

@ -0,0 +1,151 @@
# 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

@ -0,0 +1,29 @@
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

@ -0,0 +1,45 @@
# Angel3 Container
![Pub Version (including pre-releases)](https://img.shields.io/pub/v/angel3_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 Angel3, ultimately allowing Angel3 to be used with or without `dart:mirrors` package.
```dart
import 'package:angel3_container/mirrors.dart';
import 'package:angel3_framework/angel3_framework.dart';
import 'package:angel3_framework/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 = Angel(reflector: MirrorsReflector());
// Sales Controller
app.container.registerSingleton<SalesController>(SalesController());
await app.mountController<SalesController>();
var http = AngelHttp(app);
var server = await http.startServer('localhost', 3000);
print("Angel3 server listening at ${http.uri}");
}
```

View file

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

View file

@ -0,0 +1,75 @@
import 'dart:async';
import 'package:platform_container/platform_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

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

View file

@ -0,0 +1 @@
export 'src/mirrors/mirrors.dart';

View file

@ -0,0 +1,9 @@
library angel3_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

@ -0,0 +1,239 @@
import 'dart:async';
import 'exception.dart';
import 'reflector.dart';
class Container {
final Reflector reflector;
final Map<Type, dynamic> _singletons = {};
final Map<Type, dynamic Function(Container)> _factories = {};
final Map<String, dynamic> _namedSingletons = {};
final Container? _parent;
Container(this.reflector) : _parent = null;
Container._child(Container this._parent) : reflector = _parent.reflector;
bool get isRoot => _parent == null;
/// Creates a child [Container] that can define its own singletons and factories.
///
/// Use this to create children of a global "scope."
Container createChild() {
return Container._child(this);
}
/// Determines if the container has an injection of the given type.
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 has a named singleton with the given [name].
bool hasNamed(String name) {
Container? search = this;
while (search != null) {
if (search._namedSingletons.containsKey(name)) {
return true;
} else {
search = search._parent;
}
}
return false;
}
/// Instantiates an instance of [T], asynchronously.
///
/// It is similar to [make], but resolves an injection of either
/// `Future<T>` or `T`.
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].
///
/// In contexts where a static generic type cannot be used, use
/// the [type] argument, instead of [T].
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.');
}
}
/// Shorthand for registering a factory that injects a singleton when it runs.
///
/// 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. Any attempt to resolve the
/// type within *this* container will return the result of [f].
///
/// 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. Any attempt to resolve the
/// type within *this* container will return [object].
///
/// 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;
}
/// Finds a named singleton.
///
/// 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.
///
/// 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

@ -0,0 +1,8 @@
class ContainerConst {
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.';
ContainerConst._();
}

View file

@ -0,0 +1,112 @@
import '../../platform_container.dart';
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.
class EmptyReflector extends Reflector {
/// A [RegExp] that can be used to extract the name of a symbol without reflection.
static final RegExp symbolRegex = RegExp(r'Symbol\("([^"]+)"\)');
const EmptyReflector();
@override
String? getName(Symbol symbol) {
return _symbolNames.putIfAbsent(
symbol, () => symbolRegex.firstMatch(symbol.toString())?.group(1));
}
@override
ReflectedClass reflectClass(Type clazz) {
return const _EmptyReflectedClass();
}
@override
ReflectedInstance reflectInstance(Object object) {
return const _EmptyReflectedInstance();
}
@override
ReflectedType reflectType(Type type) {
return const _EmptyReflectedType();
}
@override
ReflectedFunction reflectFunction(Function function) {
return const _EmptyReflectedFunction();
}
}
class _EmptyReflectedClass extends ReflectedClass {
const _EmptyReflectedClass()
: super(
'(empty)',
const <ReflectedTypeParameter>[],
const <ReflectedInstance>[],
const <ReflectedFunction>[],
const <ReflectedDeclaration>[],
Object);
@override
ReflectedInstance newInstance(
String constructorName, List positionalArguments,
[Map<String, dynamic>? namedArguments, List<Type>? typeArguments]) {
throw UnsupportedError(
'Classes reflected via an EmptyReflector cannot be instantiated.');
}
@override
bool isAssignableTo(ReflectedType? other) {
return other == this;
}
}
class _EmptyReflectedType extends ReflectedType {
const _EmptyReflectedType()
: super('(empty)', const <ReflectedTypeParameter>[], Object);
@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.');
}
@override
bool isAssignableTo(ReflectedType? other) {
return other == this;
}
}
class _EmptyReflectedInstance extends ReflectedInstance {
const _EmptyReflectedInstance()
: super(const _EmptyReflectedType(), const _EmptyReflectedClass(), null);
@override
ReflectedInstance getField(String name) {
throw UnsupportedError(
'Instances reflected via an EmptyReflector cannot call getField().');
}
}
class _EmptyReflectedFunction extends ReflectedFunction {
const _EmptyReflectedFunction()
: super(
'(empty)',
const <ReflectedTypeParameter>[],
const <ReflectedInstance>[],
const <ReflectedParameter>[],
false,
false,
returnType: const _EmptyReflectedType());
@override
ReflectedInstance invoke(Invocation invocation) {
throw UnsupportedError(
'Instances reflected via an EmptyReflector cannot call invoke().');
}
}

View file

@ -0,0 +1,8 @@
class ReflectionException implements Exception {
final String message;
ReflectionException(this.message);
@override
String toString() => message;
}

View file

@ -0,0 +1 @@
export 'reflector.dart';

View file

@ -0,0 +1,252 @@
import 'dart:async';
import 'dart:mirrors' as dart;
import '../exception.dart';
import '../reflector.dart';
import 'package:quiver/core.dart';
/// A [Reflector] implementation that forwards to `dart:mirrors`.
///
/// Useful on the server, where reflection is supported.
class MirrorsReflector extends Reflector {
const MirrorsReflector();
@override
String getName(Symbol symbol) => dart.MirrorSystem.getName(symbol);
@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.');
}
}
@override
ReflectedFunction reflectFunction(Function function) {
var closure = dart.reflect(function) as dart.ClosureMirror;
return _ReflectedMethodMirror(closure.function, closure);
}
@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);
}
}
}
@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);
}
@override
ReflectedInstance reflectInstance(Object object) {
return _ReflectedInstanceMirror(dart.reflect(object));
}
}
class _ReflectedTypeParameter extends ReflectedTypeParameter {
final dart.TypeVariableMirror mirror;
_ReflectedTypeParameter(this.mirror)
: super(dart.MirrorSystem.getName(mirror.simpleName));
}
class _ReflectedTypeMirror extends ReflectedType {
final dart.TypeMirror mirror;
_ReflectedTypeMirror(this.mirror)
: super(
dart.MirrorSystem.getName(mirror.simpleName),
mirror.typeVariables.map((m) => _ReflectedTypeParameter(m)).toList(),
mirror.reflectedType,
);
@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;
}
}
@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.');
}
}
class _ReflectedClassMirror extends ReflectedClass {
final dart.ClassMirror mirror;
_ReflectedClassMirror(this.mirror)
: super(
dart.MirrorSystem.getName(mirror.simpleName),
mirror.typeVariables.map((m) => _ReflectedTypeParameter(m)).toList(),
[],
[],
_declarationsOf(mirror),
mirror.reflectedType,
);
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;
}
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;
}
@override
List<ReflectedInstance> get annotations =>
mirror.metadata.map((m) => _ReflectedInstanceMirror(m)).toList();
@override
List<ReflectedFunction> get constructors => _constructorsOf(mirror);
@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;
}
}
@override
ReflectedInstance newInstance(
String constructorName, List positionalArguments,
[Map<String, dynamic>? namedArguments, List<Type>? typeArguments]) {
return _ReflectedInstanceMirror(
mirror.newInstance(Symbol(constructorName), positionalArguments));
}
@override
bool operator ==(other) {
return other is _ReflectedClassMirror && other.mirror == mirror;
}
@override
int get hashCode => hash2(mirror, " ");
}
class _ReflectedDeclarationMirror extends ReflectedDeclaration {
final dart.MethodMirror mirror;
_ReflectedDeclarationMirror(String name, this.mirror)
: super(name, mirror.isStatic, null);
@override
bool get isStatic => mirror.isStatic;
@override
ReflectedFunction get function => _ReflectedMethodMirror(mirror);
}
class _ReflectedInstanceMirror extends ReflectedInstance {
final dart.InstanceMirror mirror;
_ReflectedInstanceMirror(this.mirror)
: super(_ReflectedClassMirror(mirror.type),
_ReflectedClassMirror(mirror.type), mirror.reflectee);
@override
ReflectedInstance getField(String name) {
return _ReflectedInstanceMirror(mirror.getField(Symbol(name)));
}
}
class _ReflectedMethodMirror extends ReflectedFunction {
final dart.MethodMirror mirror;
final dart.ClosureMirror? closureMirror;
_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));
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);
}
@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

@ -0,0 +1,189 @@
import 'package:collection/collection.dart';
import 'package:quiver/core.dart';
abstract class Reflector {
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`.');
}
}
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);
}
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);
}
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);
}
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;
}
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);
}
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

@ -0,0 +1,61 @@
import '../reflector.dart';
/// A [Reflector] implementation that performs simple [Map] lookups.
///
/// `package:angel_container_generator` uses this to create reflectors from analysis metadata.
class StaticReflector extends Reflector {
final Map<Symbol, String> names;
final Map<Type, ReflectedType> types;
final Map<Function, ReflectedFunction> functions;
final Map<Object, ReflectedInstance> instances;
const StaticReflector(
{this.names = const {},
this.types = const {},
this.functions = const {},
this.instances = const {}});
@override
String? getName(Symbol symbol) {
if (!names.containsKey(symbol)) {
throw ArgumentError(
'The value of $symbol is unknown - it was not generated.');
}
return names[symbol];
}
@override
ReflectedClass? reflectClass(Type clazz) =>
reflectType(clazz) as ReflectedClass?;
@override
ReflectedFunction? reflectFunction(Function function) {
if (!functions.containsKey(function)) {
throw ArgumentError(
'There is no reflection information available about $function.');
}
return functions[function];
}
@override
ReflectedInstance? reflectInstance(Object object) {
if (!instances.containsKey(object)) {
throw ArgumentError(
'There is no reflection information available about $object.');
}
return instances[object];
}
@override
ReflectedType? reflectType(Type type) {
if (!types.containsKey(type)) {
throw ArgumentError(
'There is no reflection information available about $type.');
}
return types[type];
}
}

View file

@ -0,0 +1,40 @@
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.';
*/
const ThrowingReflector(
{this.errorMessage = ContainerConst.defaultErrorMessage});
@override
String? getName(Symbol symbol) => const EmptyReflector().getName(symbol);
UnsupportedError _error() => UnsupportedError(errorMessage);
@override
ReflectedClass reflectClass(Type clazz) => throw _error();
@override
ReflectedInstance reflectInstance(Object object) => throw _error();
@override
ReflectedType reflectType(Type type) => throw _error();
@override
ReflectedFunction reflectFunction(Function function) => throw _error();
}

View file

@ -0,0 +1,13 @@
name: platform_container
version: 9.0.0
description: Protevus Platform hierarchical DI container, and pluggable backends for reflection.
homepage: https://angel3-framework.web.app/
repository: https://github.com/dart-backend/angel/tree/master/packages/container/angel_container
environment:
sdk: '>=3.3.0 <4.0.0'
dependencies:
collection: ^1.17.0
quiver: ^3.2.0
dev_dependencies:
test: ^1.24.0
lints: ^4.0.0

View file

@ -0,0 +1,122 @@
import 'dart:async';
import 'package:platform_container/platform_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

@ -0,0 +1,138 @@
import 'package:platform_container/platform_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

@ -0,0 +1,51 @@
import 'package:platform_container/platform_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

@ -0,0 +1,18 @@
import 'package:platform_container/platform_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);
}

View file

@ -0,0 +1,26 @@
import 'dart:async';
import 'package:platform_container/platform_container.dart';
import 'package:platform_container/mirrors.dart';
import 'package:test/test.dart';
import 'common.dart';
void main() {
testReflector(const MirrorsReflector());
test('futureOf', () {
var r = MirrorsReflector();
var fStr = r.reflectFutureOf(String);
expect(fStr.reflectedType.toString(), 'Future<String>');
// expect(fStr.reflectedType, Future<String>.value(null).runtimeType);
});
test('concrete future make', () async {
var c = Container(MirrorsReflector());
c.registerFactory<Future<String>>((_) async => 'hey');
var fStr = c.reflector.reflectFutureOf(String);
var s1 = await c.make(fStr.reflectedType);
var s2 = await c.makeAsync(String);
print([s1, s2]);
expect(s1, s2);
});
}

View file

@ -0,0 +1,34 @@
import 'package:platform_container/platform_container.dart';
import 'package:test/test.dart';
void main() {
late Container container;
setUp(() {
container = Container(const EmptyReflector());
container.registerNamedSingleton('foo', Foo(bar: 'baz'));
});
test('fetch by name', () {
expect(container.findByName<Foo>('foo').bar, 'baz');
});
test('cannot redefine', () {
expect(() => container.registerNamedSingleton('foo', Foo(bar: 'quux')),
throwsStateError);
});
test('throws on unknown name', () {
expect(() => container.findByName('bar'), throwsStateError);
});
test('throws on incorrect type', () {
expect(() => container.findByName<List<String>>('foo'), throwsA(anything));
});
}
class Foo {
final String? bar;
Foo({this.bar});
}

View file

@ -0,0 +1,36 @@
import 'package:platform_container/platform_container.dart';
import 'package:test/test.dart';
void main() {
var reflector = const ThrowingReflector();
test('getName', () {
expect(reflector.getName(#foo), 'foo');
expect(reflector.getName(#==), '==');
});
test('reflectClass fails', () {
expect(() => reflector.reflectClass(Truck), throwsUnsupportedError);
});
test('reflectType fails', () {
expect(() => reflector.reflectType(Truck), throwsUnsupportedError);
});
test('reflectFunction throws', () {
void doIt(int x) {}
expect(() => reflector.reflectFunction(doIt), throwsUnsupportedError);
});
test('reflectInstance throws', () {
expect(() => reflector.reflectInstance(Truck()), throwsUnsupportedError);
});
}
class Truck {
int get wheelCount => 4;
void drive() {
print('Vroom!!!');
}
}

View file

@ -0,0 +1,13 @@
# See https://www.dartlang.org/guides/libraries/private-files
# 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/

View file

@ -0,0 +1,58 @@
# 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.1
* Require Dart >= 2.19
* Upgraded `relectable` to 4.x.x
## 7.0.0
* Require Dart >= 2.17
## 6.0.0
* Require Dart >= 2.16
## 5.0.0
* Skipped release
## 4.0.0
* Skipped release
## 3.0.1
* Updated `package:angel3_container`
## 3.0.0
* Fixed NNBD issues
* All 9 test cases passed
## 3.0.0-beta.1
* Migrated to support Dart >= 2.12 NNBD
* Updated linter to `package:lints`
* Updated to use `angel3_` packages
## 2.0.0
* Migrated to work with Dart >= 2.12 Non NNBD
## 1.0.1
* Update for `pkg:angel_container@1.0.3`.

View file

@ -0,0 +1,29 @@
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

@ -0,0 +1,32 @@
# Angel3 Container Generator
![Pub Version (including pre-releases)](https://img.shields.io/pub/v/angel3_container_generator?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/angel3_container_generator/LICENSE)
An alternative container for Angel3 that uses `reflectable` package instead of `dart:mirrors` for reflection. However, `reflectable` has more limited relfection capabilities when compared to `dart:mirrors`.
## Usage
* Annotable the class with `@contained`.
* Run `dart run build_runner build <Your class directory>`
* Alternatively create a `build.xml` file with the following content
```yaml
targets:
$default:
builders:
reflectable:
generate_for:
- bin/**_controller.dart
options:
formatted: true
```
## Known limitation
* `analyser` 6.x is not supported due to `reflectable`
* Reflection on functions/closures is not supported
* Reflection on private declarations is not supported
* Reflection on generic type is not supported

View file

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

View file

@ -0,0 +1,75 @@
import 'dart:async';
import 'package:platform_container/platform_container.dart';
import 'package:platform_container_generator/angel3_container_generator.dart';
Future<void> main() async {
// Create a container instance.
Container container = Container(GeneratedReflector());
// 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.');
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,255 @@
import 'package:platform_container/platform_container.dart';
import 'package:reflectable/reflectable.dart';
/// A [Reflectable] instance that can be used as an annotation on types to generate metadata for them.
const Reflectable contained = ContainedReflectable();
@contained
class ContainedReflectable extends Reflectable {
const ContainedReflectable()
: super(
topLevelInvokeCapability,
typeAnnotationQuantifyCapability,
superclassQuantifyCapability,
libraryCapability,
invokingCapability,
metadataCapability,
reflectedTypeCapability,
typeCapability,
typingCapability);
}
/// A [Reflector] instance that uses a [Reflectable] to reflect upon data.
class GeneratedReflector extends Reflector {
final Reflectable reflectable;
const GeneratedReflector([this.reflectable = contained]);
@override
String getName(Symbol symbol) {
return symbol.toString().substring(7);
}
@override
ReflectedClass reflectClass(Type clazz) {
return reflectType(clazz) as ReflectedClass;
}
@override
ReflectedFunction reflectFunction(Function function) {
if (!reflectable.canReflect(function)) {
throw UnsupportedError('Cannot reflect $function.');
}
var mirror = reflectable.reflect(function);
if (mirror is ClosureMirror) {
return _GeneratedReflectedFunction(mirror.function, this, mirror);
} else {
throw ArgumentError('$function is not a Function.');
}
}
@override
ReflectedInstance reflectInstance(Object object) {
if (!reflectable.canReflect(object)) {
throw UnsupportedError('Cannot reflect $object.');
} else {
var mirror = reflectable.reflect(object);
return _GeneratedReflectedInstance(mirror, this);
}
}
@override
ReflectedType reflectType(Type type) {
if (!reflectable.canReflectType(type)) {
throw UnsupportedError('Cannot reflect $type.');
} else {
var mirror = reflectable.reflectType(type);
return mirror is ClassMirror
? _GeneratedReflectedClass(mirror, this)
: _GeneratedReflectedType(mirror);
}
}
}
class _GeneratedReflectedInstance extends ReflectedInstance {
final InstanceMirror mirror;
final GeneratedReflector reflector;
_GeneratedReflectedInstance(this.mirror, this.reflector)
: super(_GeneratedReflectedType(mirror.type),
_GeneratedReflectedClass(mirror.type, reflector), mirror.reflectee);
@override
ReflectedType get type => clazz;
@override
ReflectedInstance getField(String name) {
var result = mirror.invokeGetter(name)!;
var instance = reflector.reflectable.reflect(result);
return _GeneratedReflectedInstance(instance, reflector);
}
}
class _GeneratedReflectedClass extends ReflectedClass {
final ClassMirror mirror;
final Reflector reflector;
_GeneratedReflectedClass(this.mirror, this.reflector)
: super(mirror.simpleName, [], [], [], [], mirror.reflectedType);
@override
List<ReflectedTypeParameter> get typeParameters =>
mirror.typeVariables.map(_convertTypeVariable).toList();
@override
List<ReflectedFunction> get constructors =>
_constructorsOf(mirror.declarations, reflector);
@override
List<ReflectedDeclaration> get declarations =>
_declarationsOf(mirror.declarations, reflector);
@override
List<ReflectedInstance> get annotations => mirror.metadata
.map(reflector.reflectInstance)
.whereType<ReflectedInstance>()
.toList();
@override
bool isAssignableTo(ReflectedType? other) {
if (other is _GeneratedReflectedClass) {
return mirror.isAssignableTo(other.mirror);
} else if (other is _GeneratedReflectedType) {
return mirror.isAssignableTo(other.mirror);
} else {
return false;
}
}
@override
ReflectedInstance newInstance(
String constructorName, List positionalArguments,
[Map<String, dynamic>? namedArguments, List<Type>? typeArguments]) {
namedArguments ??= {};
var result = mirror.newInstance(constructorName, positionalArguments,
namedArguments.map((k, v) => MapEntry(Symbol(k), v)));
return reflector.reflectInstance(result)!;
}
}
class _GeneratedReflectedType extends ReflectedType {
final TypeMirror mirror;
_GeneratedReflectedType(this.mirror)
: super(mirror.simpleName, [], mirror.reflectedType);
@override
List<ReflectedTypeParameter> get typeParameters =>
mirror.typeVariables.map(_convertTypeVariable).toList();
@override
bool isAssignableTo(ReflectedType? other) {
if (other is _GeneratedReflectedClass) {
return mirror.isAssignableTo(other.mirror);
} else if (other is _GeneratedReflectedType) {
return mirror.isAssignableTo(other.mirror);
} else {
return false;
}
}
@override
ReflectedInstance newInstance(
String constructorName, List positionalArguments,
[Map<String, dynamic> namedArguments = const {},
List<Type> typeArguments = const []]) {
throw UnsupportedError('Cannot create a new instance of $reflectedType.');
}
}
class _GeneratedReflectedFunction extends ReflectedFunction {
final MethodMirror mirror;
final Reflector reflector;
final ClosureMirror? closure;
_GeneratedReflectedFunction(this.mirror, this.reflector, [this.closure])
: super(
mirror.simpleName,
[],
[],
mirror.parameters
.map((p) => _convertParameter(p, reflector))
.toList(),
mirror.isGetter,
mirror.isSetter,
returnType: !mirror.isRegularMethod
? null
: _GeneratedReflectedType(mirror.returnType));
@override
List<ReflectedInstance> get annotations => mirror.metadata
.map(reflector.reflectInstance)
.whereType<ReflectedInstance>()
.toList();
@override
ReflectedInstance invoke(Invocation invocation) {
if (closure != null) {
throw UnsupportedError('Only closures can be invoked directly.');
} else {
var result = closure!.delegate(invocation)!;
return reflector.reflectInstance(result)!;
}
}
}
List<ReflectedFunction> _constructorsOf(
Map<String, DeclarationMirror> map, Reflector reflector) {
return map.entries.fold<List<ReflectedFunction>>([], (out, entry) {
var v = entry.value;
if (v is MethodMirror && v.isConstructor) {
return out..add(_GeneratedReflectedFunction(v, reflector));
} else {
return out;
}
});
}
List<ReflectedDeclaration> _declarationsOf(
Map<String, DeclarationMirror> map, Reflector reflector) {
return map.entries.fold<List<ReflectedDeclaration>>([], (out, entry) {
var v = entry.value;
if (v is VariableMirror) {
var decl = ReflectedDeclaration(v.simpleName, v.isStatic, null);
return out..add(decl);
}
if (v is MethodMirror) {
var decl = ReflectedDeclaration(
v.simpleName, v.isStatic, _GeneratedReflectedFunction(v, reflector));
return out..add(decl);
} else {
return out;
}
});
}
ReflectedTypeParameter _convertTypeVariable(TypeVariableMirror mirror) {
return ReflectedTypeParameter(mirror.simpleName);
}
ReflectedParameter _convertParameter(
ParameterMirror mirror, Reflector reflector) {
return ReflectedParameter(
mirror.simpleName,
mirror.metadata
.map(reflector.reflectInstance)
.whereType<ReflectedInstance>()
.toList(),
reflector.reflectType(mirror.type.reflectedType)!,
!mirror.isOptional,
mirror.isNamed);
}

View file

@ -0,0 +1,18 @@
name: platform_container_generator
version: 9.0.0
description: Codegen support for using pkg:reflectable with pkg:angel3_container.
homepage: https://angel3-framework.web.app/
repository: https://github.com/dart-backend/angel/tree/master/packages/container/angel_container_generator
environment:
sdk: '>=3.3.0 <4.0.0'
dependencies:
platform_container: ^9.0.0
reflectable: ^4.0.0
dev_dependencies:
build_runner: ^2.4.0
build_test: ^2.1.0
test: ^1.24.0
lints: ^4.0.0
# dependency_overrides:
# angel3_container:
# path: ../angel_container

View file

@ -0,0 +1,179 @@
import 'package:platform_container/platform_container.dart';
import 'package:platform_container_generator/angel3_container_generator.dart';
import 'package:test/test.dart';
import 'reflector_test.reflectable.dart';
void main() {
initializeReflectable();
var reflector = const GeneratedReflector();
late Container container;
setUp(() {
container = Container(reflector);
container.registerSingleton(Artist(name: 'Stevie Wonder'));
});
group('reflectClass', () {
var mirror = reflector.reflectClass(Artist);
test('name', () {
expect(mirror.name, 'Artist');
});
});
test('inject constructor parameters', () {
var album = container.make<Album>();
print(album.title);
expect(album.title, 'flowers by stevie wonder');
});
// Skip as pkg:reflectable cannot reflect on closures at all (yet)
//testReflector(reflector);
}
@contained
void returnVoidFromAFunction(int x) {}
void testReflector(Reflector reflector) {
var blaziken = Pokemon('Blaziken', PokemonType.fire);
late Container container;
setUp(() {
container = Container(reflector);
container.registerSingleton(blaziken);
});
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));
});
}, skip: 'pkg:reflectable cannot reflect on closures at all (yet)');
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 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);
});
}
@contained
class LowerPokemon {
final Pokemon pokemon;
LowerPokemon(this.pokemon);
String get lowercaseName => pokemon.name.toLowerCase();
}
@contained
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';
}
@contained
class KantoPokemon extends Pokemon {
KantoPokemon(super.name, super.type);
}
@contained
enum PokemonType { water, fire, grass, ice, poison, flying }
@contained
class Artist {
final String name;
Artist({required this.name});
String get lowerName {
return name.toLowerCase();
}
}
@contained
class Album {
final Artist artist;
Album(this.artist);
String get title => 'flowers by ${artist.lowerName}';
}
@contained
class AlbumLength {
final Artist artist;
final Album album;
AlbumLength(this.artist, this.album);
int get totalLength => artist.name.length + album.title.length;
}

File diff suppressed because it is too large Load diff