optional expose
This commit is contained in:
parent
91bc517b1f
commit
0a9b5c118f
4 changed files with 72 additions and 8 deletions
|
@ -1,4 +1,5 @@
|
||||||
# 2.0.5
|
# 2.0.5
|
||||||
|
* Make `@Expose()` in `Controller` optional. https://github.com/angel-dart/angel/issues/107
|
||||||
* Add `allowHttp1` to `AngelHttp2` constructors. https://github.com/angel-dart/angel/issues/108
|
* Add `allowHttp1` to `AngelHttp2` constructors. https://github.com/angel-dart/angel/issues/108
|
||||||
* Add `deserializeBody` and `decodeBody` to `RequestContext`. https://github.com/angel-dart/angel/issues/109
|
* Add `deserializeBody` and `decodeBody` to `RequestContext`. https://github.com/angel-dart/angel/issues/109
|
||||||
* Add `HostnameRouter`, which allows for routing based on hostname. https://github.com/angel-dart/angel/issues/110
|
* Add `HostnameRouter`, which allows for routing based on hostname. https://github.com/angel-dart/angel/issues/110
|
||||||
|
|
|
@ -4,7 +4,7 @@ import 'dart:async';
|
||||||
import 'package:angel_container/angel_container.dart';
|
import 'package:angel_container/angel_container.dart';
|
||||||
import 'package:angel_route/angel_route.dart';
|
import 'package:angel_route/angel_route.dart';
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
|
import 'package:recase/recase.dart';
|
||||||
import '../core/core.dart';
|
import '../core/core.dart';
|
||||||
|
|
||||||
/// Supports grouping routes with shared functionality.
|
/// Supports grouping routes with shared functionality.
|
||||||
|
@ -86,7 +86,15 @@ class Controller {
|
||||||
.map((m) => m.reflectee)
|
.map((m) => m.reflectee)
|
||||||
.firstWhere((r) => r is Expose, orElse: () => null) as Expose;
|
.firstWhere((r) => r is Expose, orElse: () => null) as Expose;
|
||||||
|
|
||||||
if (exposeDecl == null) return;
|
if (exposeDecl == null) {
|
||||||
|
// If this has a @noExpose, return null.
|
||||||
|
if (decl.function.annotations.any((m) => m.reflectee is NoExpose)) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// Otherwise, create an @Expose.
|
||||||
|
exposeDecl = Expose(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var reflectedMethod =
|
var reflectedMethod =
|
||||||
instanceMirror.getField(methodName).reflectee as Function;
|
instanceMirror.getField(methodName).reflectee as Function;
|
||||||
|
@ -117,6 +125,30 @@ class Controller {
|
||||||
injection.optional?.addAll(exposeDecl.allowNull);
|
injection.optional?.addAll(exposeDecl.allowNull);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If there is no path, reverse-engineer one.
|
||||||
|
var path = exposeDecl.path;
|
||||||
|
if (path == null) {
|
||||||
|
var parts = <String>[];
|
||||||
|
parts.add(ReCase(method.name).snakeCase.replaceAll(_multiScore, '_'));
|
||||||
|
|
||||||
|
// Try to infer String, int, or double.
|
||||||
|
for (var p in injection.required) {
|
||||||
|
if (p is List && p.length == 2 && p[0] is String && p[1] is Type) {
|
||||||
|
var name = p[0] as String;
|
||||||
|
var type = p[1] as Type;
|
||||||
|
if (type == String) {
|
||||||
|
parts.add(':$name');
|
||||||
|
} else if (type == int) {
|
||||||
|
parts.add('int:$name');
|
||||||
|
} else if (type == double) {
|
||||||
|
parts.add('double:$name');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
path = parts.join('/');
|
||||||
|
}
|
||||||
|
|
||||||
routeMappings[name] = routable.addRoute(exposeDecl.method,
|
routeMappings[name] = routable.addRoute(exposeDecl.method,
|
||||||
exposeDecl.path, handleContained(reflectedMethod, injection),
|
exposeDecl.path, handleContained(reflectedMethod, injection),
|
||||||
middleware: middleware);
|
middleware: middleware);
|
||||||
|
@ -127,10 +159,22 @@ class Controller {
|
||||||
/// Used to add additional routes to the router from within a [Controller].
|
/// Used to add additional routes to the router from within a [Controller].
|
||||||
void configureRoutes(Routable routable) {}
|
void configureRoutes(Routable routable) {}
|
||||||
|
|
||||||
|
static final RegExp _multiScore = RegExp(r'__+');
|
||||||
|
|
||||||
/// Finds the [Expose] declaration for this class.
|
/// Finds the [Expose] declaration for this class.
|
||||||
Expose findExpose(Reflector reflector) => reflector
|
Expose findExpose(Reflector reflector, {bool concreteOnly = false}) {
|
||||||
|
var existing = reflector
|
||||||
.reflectClass(runtimeType)
|
.reflectClass(runtimeType)
|
||||||
.annotations
|
.annotations
|
||||||
.map((m) => m.reflectee)
|
.map((m) => m.reflectee)
|
||||||
.firstWhere((r) => r is Expose, orElse: () => null) as Expose;
|
.firstWhere((r) => r is Expose, orElse: () => null) as Expose;
|
||||||
|
return existing ??
|
||||||
|
(concreteOnly
|
||||||
|
? null
|
||||||
|
: Expose(ReCase(runtimeType.toString())
|
||||||
|
.snakeCase
|
||||||
|
.replaceAll('_controller', '')
|
||||||
|
.replaceAll('_ctrl', '')
|
||||||
|
.replaceAll(_multiScore, '_')));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,14 @@ class Hooks {
|
||||||
const Hooks({this.before = const [], this.after = const []});
|
const Hooks({this.before = const [], this.after = const []});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Exposes a [Controller] to the Internet.
|
/// Specifies to NOT expose a method to the Internet.
|
||||||
|
class NoExpose {
|
||||||
|
const NoExpose();
|
||||||
|
}
|
||||||
|
|
||||||
|
const NoExpose noExpose = NoExpose();
|
||||||
|
|
||||||
|
/// Exposes a [Controller] or method to the Internet.
|
||||||
class Expose {
|
class Expose {
|
||||||
final String method;
|
final String method;
|
||||||
final String path;
|
final String path;
|
||||||
|
@ -29,11 +36,22 @@ class Expose {
|
||||||
final String as;
|
final String as;
|
||||||
final List<String> allowNull;
|
final List<String> allowNull;
|
||||||
|
|
||||||
|
static const Expose get = Expose(null, method: 'GET'),
|
||||||
|
post = Expose(null, method: 'POST'),
|
||||||
|
patch = Expose(null, method: 'PATCH'),
|
||||||
|
put = Expose(null, method: 'PUT'),
|
||||||
|
delete = Expose(null, method: 'DELETE'),
|
||||||
|
head = Expose(null, method: 'HEAD');
|
||||||
|
|
||||||
const Expose(this.path,
|
const Expose(this.path,
|
||||||
{this.method = "GET",
|
{this.method = "GET",
|
||||||
this.middleware = const [],
|
this.middleware = const [],
|
||||||
this.as,
|
this.as,
|
||||||
this.allowNull = const []});
|
this.allowNull = const []});
|
||||||
|
|
||||||
|
const Expose.method(this.method,
|
||||||
|
{this.middleware, this.as, this.allowNull = const []})
|
||||||
|
: path = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used to apply special dependency injections or functionality to a function parameter.
|
/// Used to apply special dependency injections or functionality to a function parameter.
|
||||||
|
|
|
@ -25,6 +25,7 @@ dependencies:
|
||||||
path: ^1.0.0
|
path: ^1.0.0
|
||||||
pedantic: ^1.0.0
|
pedantic: ^1.0.0
|
||||||
quiver_hashcode: ^2.0.0
|
quiver_hashcode: ^2.0.0
|
||||||
|
recase: ^2.0.0
|
||||||
stack_trace: ^1.0.0
|
stack_trace: ^1.0.0
|
||||||
tuple: ^1.0.0
|
tuple: ^1.0.0
|
||||||
uuid: ^2.0.0-rc.1
|
uuid: ^2.0.0-rc.1
|
||||||
|
|
Loading…
Reference in a new issue