This commit is contained in:
Tobe O 2017-11-24 19:26:06 -05:00
parent 57b2bdff87
commit 4357a102da
11 changed files with 56 additions and 83 deletions

View file

@ -1,6 +1,5 @@
library angel_route;
export 'src/extensible.dart';
export 'src/middleware_pipeline.dart';
export 'src/router.dart';
export 'src/routing_exception.dart';

View file

@ -108,7 +108,7 @@ class _HashRouter extends _BrowserRouterImpl {
void handleHash([_]) {
final path = window.location.hash.replaceAll(_hash, '');
final resolved = resolveAbsolute(path);
final resolved = resolveAbsolute(path).first;
if (resolved == null) {
_onResolve.add(null);
@ -120,7 +120,7 @@ class _HashRouter extends _BrowserRouterImpl {
}
void handlePath(String path) {
final resolved = resolveAbsolute(path);
final resolved = resolveAbsolute(path).first;
if (resolved == null) {
_onResolve.add(null);
@ -153,7 +153,7 @@ class _PushStateRouter extends _BrowserRouterImpl {
@override
void _goTo(String uri) {
final resolved = resolveAbsolute(uri);
final resolved = resolveAbsolute(uri).first;
var relativeUri = uri;
if (_basePath?.isNotEmpty == true) {
@ -177,13 +177,12 @@ class _PushStateRouter extends _BrowserRouterImpl {
void handleState(state) {
if (state is Map && state.containsKey('path')) {
var path = state['path'];
final resolved = resolveAbsolute(path);
final resolved = resolveAbsolute(path).first;
if (resolved != null && resolved.route != _current) {
//properties.addAll(state['properties'] ?? {});
_onResolve.add(resolved);
_onRoute.add(_current = resolved.route
..state.properties.addAll(state['params'] ?? {}));
_onRoute.add(_current = resolved.route);
} else {
_onResolve.add(null);
_onRoute.add(_current = null);

View file

@ -1,32 +0,0 @@
final RegExp _equ = new RegExp(r'=$');
final RegExp _sym = new RegExp(r'Symbol\("([^"]+)"\)');
/// Supports accessing members of a Map as though they were actual members.
///
/// No longer requires reflection. :)
@proxy
@deprecated
class Extensible {
/// A set of custom properties that can be assigned to the server.
///
/// Useful for configuration and extension.
Map properties = {};
operator [](key) => properties[key];
operator []=(key, value) => properties[key] = value;
noSuchMethod(Invocation invocation) {
if (invocation.memberName != null) {
String name = _sym.firstMatch(invocation.memberName.toString()).group(1);
if (invocation.isMethod) {
return Function.apply(properties[name], invocation.positionalArguments,
invocation.namedArguments);
} else if (invocation.isGetter) {
return properties[name];
}
}
super.noSuchMethod(invocation);
}
}

View file

@ -4,16 +4,18 @@ import 'router.dart';
class MiddlewarePipeline {
/// All the possible routes that matched the given path.
final List<RoutingResult> routingResults;
List _handlers;
/// An ordered list of every handler delegated to handle this request.
List get handlers {
if (_handlers != null) return _handlers;
final handlers = [];
for (RoutingResult result in routingResults) {
handlers.addAll(result.allHandlers);
}
return handlers;
return _handlers = handlers;
}
MiddlewarePipeline(this.routingResults);

View file

@ -76,9 +76,6 @@ class Route {
/// The virtual path on which this route is mounted.
String get path => _path;
/// Arbitrary state attached to this route.
final Extensible state = new Extensible();
/// The [Route] at the top of the hierarchy this route is found in.
Route get absoluteParent {
Route result = this;
@ -314,8 +311,7 @@ class Route {
.._path = _path
.._pathified = _pathified
.._resolver = _resolver
.._stub = _stub
..state.properties.addAll(state.properties);
.._stub = _stub;
}
/// Generates a URI to this route with the given parameters.

View file

@ -1,6 +1,5 @@
library angel_route.src.router;
import 'extensible.dart';
import 'routing_exception.dart';
import '../string_util.dart';
part 'symlink_route.dart';
@ -266,11 +265,14 @@ class Router {
/// Finds the first [Route] that matches the given path,
/// with the given method.
RoutingResult resolve(String absolute, String relative,
{String method: 'GET'}) {
final cleanAbsolute = stripStraySlashes(absolute);
final cleanRelative = stripStraySlashes(relative);
bool resolve(String absolute, String relative, List<RoutingResult> out,
{String method: 'GET', bool strip: true}) {
final cleanAbsolute =
strip == false ? absolute : stripStraySlashes(absolute);
final cleanRelative =
strip == false ? relative : stripStraySlashes(relative);
final segments = cleanRelative.split('/').where((str) => str.isNotEmpty);
bool success = false;
//print(
// 'Now resolving $method "/$cleanRelative", absolute: $cleanAbsolute');
//print('Path segments: ${segments.toList()}');
@ -285,8 +287,7 @@ class Router {
if (match != null) {
final cleaned = s.join('/').replaceFirst(match[0], '');
var tail = cleanRelative
.replaceAll(route._head, '');
var tail = cleanRelative.replaceAll(route._head, '');
tail = stripStraySlashes(tail);
if (cleaned.isEmpty) {
@ -294,9 +295,10 @@ class Router {
// 'Matched relative "$cleanRelative" to head ${route._head
// .pattern} on $route. Tail: "$tail"');
route.router.debug = route.router.debug || debug;
final nested =
route.router.resolve(cleanAbsolute, tail, method: method);
return _dumpResult(
var nested = <RoutingResult>[];
route.router.resolve(cleanAbsolute, tail, nested,
method: method, strip: false);
var result = _dumpResult(
cleanRelative,
new RoutingResult(
match: match,
@ -305,6 +307,8 @@ class Router {
shallowRoute: route,
shallowRouter: this,
tail: tail));
out.add(result);
success = true;
}
}
}
@ -314,39 +318,35 @@ class Router {
final match = route.match(cleanRelative);
if (match != null) {
return _dumpResult(
var result = _dumpResult(
cleanRelative,
new RoutingResult(
match: match,
params: route.parseParameters(cleanRelative),
shallowRoute: route,
shallowRouter: this));
out.add(result);
success = true;
}
}
}
//print('Could not resolve path "/$cleanRelative".');
return null;
return success;
}
/// Returns the result of [resolve] with [path] passed as
/// both `absolute` and `relative`.
RoutingResult resolveAbsolute(String path, {String method: 'GET'}) =>
resolve(path, path, method: method);
Iterable<RoutingResult> resolveAbsolute(String path,
{String method: 'GET', bool strip: true}) =>
resolveAll(path, path, method: method, strip: strip);
/// Finds every possible [Route] that matches the given path,
/// with the given method.
Iterable<RoutingResult> resolveAll(String absolute, String relative,
{String method: 'GET'}) {
final router = clone();
{String method: 'GET', bool strip: true}) {
final List<RoutingResult> results = [];
var result = router.resolve(absolute, relative, method: method);
while (result != null) {
results.add(result);
result.router._routes.remove(result.route);
result = router.resolve(absolute, relative, method: method);
}
resolve(absolute, relative, results, method: method, strip: strip);
// _printDebug(
// 'Results of $method "/${absolute.replaceAll(_straySlashes, '')}": ${results.map((r) => r.route).toList()}');

View file

@ -6,7 +6,7 @@ class RoutingResult {
final Match match;
/// A nested instance, if a sub-path was matched.
final RoutingResult nested;
final Iterable<RoutingResult> nested;
/// All route params matching this route on the current sub-path.
final Map<String, dynamic> params = {};
@ -28,7 +28,7 @@ class RoutingResult {
RoutingResult get deepest {
var search = this;
while (search.nested != null) search = search.nested;
while (search?.nested?.isNotEmpty == true) search = search.nested.first;
return search;
}
@ -47,26 +47,35 @@ class RoutingResult {
/// All handlers on this sub-path and its children.
List get allHandlers {
final handlers = [];
var search = this;
while (search != null) {
handlers.addAll(search.handlers);
search = search.nested;
void crawl(RoutingResult result) {
handlers.addAll(result.handlers);
if (result.nested?.isNotEmpty == true) {
for (var r in result.nested)
crawl(r);
}
}
crawl(this);
return handlers;
}
/// All parameters on this sub-path and its children.
Map<String, dynamic> get allParams {
final Map<String, dynamic> params = {};
var search = this;
while (search != null) {
params.addAll(search.params);
search = search.nested;
void crawl(RoutingResult result) {
params.addAll(result.params);
if (result.nested?.isNotEmpty == true) {
for (var r in result.nested)
crawl(r);
}
}
crawl(this);
return params;
}

View file

@ -1,6 +1,6 @@
name: angel_route
description: A powerful, isomorphic routing library for Dart.
version: 1.0.8
version: 2.0.0
author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/angel-dart/angel_route
dev_dependencies:

View file

@ -11,7 +11,7 @@ main() {
..dumpTree();
test('nested route groups with chain', () {
var r = router.resolveAbsolute('/b/e/f')?.route;
var r = router.resolveAbsolute('/b/e/f')?.first?.route;
expect(r, isNotNull);
expect(r.handlers, hasLength(4));
expect(r.handlers, equals(['a', 'c', 'd', 'g']));

View file

@ -83,8 +83,8 @@ main() {
final res = req.response;
// Easy middleware pipeline
final results = router.resolveAll(req.uri.toString(), req.uri.toString(),
method: req.method);
final results =
router.resolveAbsolute(req.uri.toString(), method: req.method);
final pipeline = new MiddlewarePipeline(results);
if (pipeline.handlers.isEmpty) {

View file

@ -8,7 +8,7 @@ void main() {
var encoded =
'/a/' + Uri.encodeComponent('<<<') + '/b/' + Uri.encodeComponent('???');
print(encoded);
var result = router.resolveAbsolute(encoded);
var result = router.resolveAbsolute(encoded).first;
print(result.allParams);
expect(result.allParams, {
'a': '<<<',