Finally fixed router!

This commit is contained in:
thosakwe 2016-11-21 22:31:09 -05:00
parent 5241e66eff
commit 34a234cb4d
24 changed files with 385 additions and 101 deletions

View file

@ -1,6 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All Tests" type="DartTestRunConfigurationType" factoryName="Dart Test" singleton="true">
<option name="filePath" value="$PROJECT_DIR$/test/all_tests.dart" />
<method />
</configuration>
</component>

View file

@ -0,0 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Method Tests" type="DartTestRunConfigurationType" factoryName="Dart Test" folderName="Router Tests" singleton="true">
<option name="filePath" value="$PROJECT_DIR$/test/method/all_tests.dart" />
<method />
</configuration>
</component>

View file

@ -1,6 +1,6 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="Use" type="DartTestRunConfigurationType" factoryName="Dart Test" folderName="Router Tests" singleton="true"> <configuration default="false" name="Use" type="DartTestRunConfigurationType" factoryName="Dart Test" folderName="Router Tests" singleton="true">
<option name="filePath" value="$PROJECT_DIR$/test/router/use.dart" /> <option name="filePath" value="$PROJECT_DIR$/test/use.dart" />
<method /> <method />
</configuration> </configuration>
</component> </component>

1
.travis.yml Normal file
View file

@ -0,0 +1 @@
language: dart

View file

@ -1,6 +1,5 @@
/// A powerful, isomorphic routing library for Dart. /// A powerful, isomorphic routing library for Dart.
library angel_route; library angel_route;
export 'src/route.dart';
export 'src/router.dart'; export 'src/router.dart';
export 'src/routing_exception.dart'; export 'src/routing_exception.dart';

View file

@ -52,6 +52,11 @@ class _BrowserRouterImpl extends Router implements BrowserRouter {
throw new RoutingException.noSuchRoute(path); throw new RoutingException.noSuchRoute(path);
} }
@override
void listen() {
normalize();
}
void prepareAnchors() { void prepareAnchors() {
final anchors = window.document.querySelectorAll('a:not([dynamic])'); final anchors = window.document.querySelectorAll('a:not([dynamic])');
@ -85,9 +90,10 @@ class _HashRouter extends _BrowserRouterImpl {
@override @override
void listen() { void listen() {
super.listen();
window.onHashChange.listen((_) { window.onHashChange.listen((_) {
final path = window.location.hash.replaceAll(_hash, ''); final path = window.location.hash.replaceAll(_hash, '');
final resolved = resolve(path); final resolved = resolveOnRoot(path);
if (resolved == null || (path.isEmpty && resolved == root)) { if (resolved == null || (path.isEmpty && resolved == root)) {
_onRoute.add(_current = null); _onRoute.add(_current = null);
@ -115,6 +121,7 @@ class _PushStateRouter extends _BrowserRouterImpl {
@override @override
void listen() { void listen() {
super.listen();
window.onPopState.listen((e) { window.onPopState.listen((e) {
if (e.state is Map && e.state.containsKey('path')) { if (e.state is Map && e.state.containsKey('path')) {
final resolved = resolve(e.state['path']); final resolved = resolve(e.state['path']);

View file

@ -1,11 +1,4 @@
import 'extensible.dart'; part of angel_route.src.router;
import 'routing_exception.dart';
final RegExp _param = new RegExp(r':([A-Za-z0-9_]+)(\((.+)\))?');
final RegExp _rgxEnd = new RegExp(r'\$+$');
final RegExp _rgxStart = new RegExp(r'^\^+');
final RegExp _rgxStraySlashes = new RegExp(r'(^((\\/)|(/))+)|(((\\/)|(/))+$)');
final RegExp _straySlashes = new RegExp(r'(^/+)|(/+$)');
String _matcherify(String path, {bool expand: true}) { String _matcherify(String path, {bool expand: true}) {
var p = path.replaceAll(new RegExp(r'/\*$'), "*").replaceAll('/', r'\/'); var p = path.replaceAll(new RegExp(r'/\*$'), "*").replaceAll('/', r'\/');
@ -48,6 +41,7 @@ String _pathify(String path) {
class Route { class Route {
final List<Route> _children = []; final List<Route> _children = [];
final List _handlers = []; final List _handlers = [];
RegExp _head;
RegExp _matcher; RegExp _matcher;
String _method; String _method;
String _name; String _name;
@ -94,6 +88,14 @@ class Route {
return result; return result;
} }
/// Returns the [Route] instances that will respond to requests
/// to the index of this instance's path.
///
/// May return `this`.
Iterable<Route> get allIndices {
return children.where((r) => r.path.replaceAll(path, '').isEmpty);
}
/// Backtracks up the hierarchy, and builds /// Backtracks up the hierarchy, and builds
/// a sequential list of all handlers from both /// a sequential list of all handlers from both
/// this route, and every found parent route. /// this route, and every found parent route.
@ -128,6 +130,8 @@ class Route {
if (debug) print(msg); if (debug) print(msg);
} }
Route._base();
Route(Pattern path, Route(Pattern path,
{Iterable<Route> children: const [], {Iterable<Route> children: const [],
this.debug: false, this.debug: false,
@ -190,8 +194,11 @@ class Route {
name: name); name: name);
} }
var head = '';
for (int i = 0; i < segments.length; i++) { for (int i = 0; i < segments.length; i++) {
final segment = segments[i]; final segment = segments[i];
head = (head + '/$segment').replaceAll(_straySlashes, '');
if (i == segments.length - 1) { if (i == segments.length - 1) {
if (result == null) { if (result == null) {
@ -206,6 +213,8 @@ class Route {
result = result.child(segment, debug: debug, method: "*"); result = result.child(segment, debug: debug, method: "*");
} }
} }
result._head = new RegExp(_matcherify(head).replaceAll(_rgxEnd, ''));
} }
} }
@ -244,33 +253,16 @@ class Route {
parent._children.add(route parent._children.add(route
.._matcher = new RegExp('$pattern1$separator$pattern2') .._matcher = new RegExp('$pattern1$separator$pattern2')
.._head = new RegExp(_matcherify('$path1/$path2'.replaceAll(_straySlashes, '')).replaceAll(_rgxEnd, ''))
.._parent = parent .._parent = parent
.._stub = child.matcher); .._stub = child.matcher);
parent._printDebug( parent._printDebug(
"Joined '/$path1' and '/$path2', created stub: ${route._stub.pattern}"); "Joined '/$path1' and '/$path2', created head: ${route._head.pattern} and stub: ${route._stub.pattern}");
return route..debug = parent.debug || child.debug || debug; return route..debug = parent.debug || child.debug || debug;
} }
Route _inherit(Route route) {
/*
final List<Route> _children = [];
final List _handlers = [];
RegExp _matcher;
String _method;
String _name;
Route _parent;
RegExp _parentResolver;
String _path;
String _pathified;
RegExp _resolver;
RegExp _stub;
*/
return route.._parent = this;
}
/// Calls [addChild] on all given routes. /// Calls [addChild] on all given routes.
List<Route> addAll(Iterable<Route> routes, {bool join: true}) { List<Route> addAll(Iterable<Route> routes, {bool join: true}) {
return routes.map((route) => addChild(route, join: join)).toList(); return routes.map((route) => addChild(route, join: join)).toList();

View file

@ -1,7 +1,15 @@
library angel_route.src.router;
import 'extensible.dart'; import 'extensible.dart';
import 'route.dart';
import 'routing_exception.dart'; import 'routing_exception.dart';
part 'route.dart';
final RegExp _param = new RegExp(r':([A-Za-z0-9_]+)(\((.+)\))?');
final RegExp _rgxEnd = new RegExp(r'\$+$');
final RegExp _rgxStart = new RegExp(r'^\^+');
final RegExp _rgxStraySlashes = new RegExp(r'(^((\\/)|(/))+)|(((\\/)|(/))+$)');
final RegExp _slashDollar = new RegExp(r'/+\$');
final RegExp _straySlashes = new RegExp(r'(^/+)|(/+$)'); final RegExp _straySlashes = new RegExp(r'(^/+)|(/+$)');
/// An abstraction over complex [Route] trees. Use this instead of the raw API. :) /// An abstraction over complex [Route] trees. Use this instead of the raw API. :)
@ -20,7 +28,8 @@ class Router extends Extensible {
/// Provide a `root` to make this Router revolve around a pre-defined route. /// Provide a `root` to make this Router revolve around a pre-defined route.
/// Not recommended. /// Not recommended.
Router({this.debug: false, Route root}) { Router({this.debug: false, Route root}) {
_root = (_root = root ?? new _RootRoute())..debug = debug; _root = (_root = root ?? new _RootRoute())
..debug = debug;
} }
void _printDebug(msg) { void _printDebug(msg) {
@ -40,7 +49,10 @@ class Router extends Extensible {
if (path is RegExp) { if (path is RegExp) {
return root.child(path, debug: debug, handlers: handlers, method: method); return root.child(path, debug: debug, handlers: handlers, method: method);
} else if (path.toString().replaceAll(_straySlashes, '').isEmpty) { } else if (path
.toString()
.replaceAll(_straySlashes, '')
.isEmpty) {
return root.child(path.toString(), return root.child(path.toString(),
debug: debug, handlers: handlers, method: method); debug: debug, handlers: handlers, method: method);
} else { } else {
@ -55,8 +67,8 @@ class Router extends Extensible {
return new Route('/', debug: debug, handlers: handlers, method: method) return new Route('/', debug: debug, handlers: handlers, method: method)
..debug = debug; ..debug = debug;
} else { } else {
result = resolve(segments[0], result = resolveOnRoot(segments[0],
(route) => route.method == method || route.method == '*'); filter: (route) => route.method == method || route.method == '*');
if (result != null) { if (result != null) {
if (segments.length > 1) { if (segments.length > 1) {
@ -68,7 +80,7 @@ class Router extends Extensible {
do { do {
existing = result.resolve(segments[0], existing = result.resolve(segments[0],
filter: (route) => filter: (route) =>
route.method == method || route.method == '*'); route.method == method || route.method == '*');
if (existing != null) { if (existing != null) {
result = existing; result = existing;
@ -110,15 +122,17 @@ class Router extends Extensible {
final buf = new StringBuffer(); final buf = new StringBuffer();
void dumpRoute(Route route, {Pattern replace: null}) { void dumpRoute(Route route, {Pattern replace: null}) {
for (var i = 0; i < tabs; i++) buf.write(tab); for (var i = 0; i < tabs; i++)
buf.write(tab);
if (route == root) if (route == root)
buf.write('(root)'); buf.writeln('(root)');
else { else {
buf.write('- ${route.method} '); buf.write('- ${route.method} ');
final p = var p =
replace != null ? route.path.replaceAll(replace, '') : route.path; replace != null ? route.path.replaceAll(replace, '') : route.path;
p = p.replaceAll(_straySlashes, '');
if (p.isEmpty) if (p.isEmpty)
buf.write("'/'"); buf.write("'/'");
@ -154,7 +168,7 @@ class Router extends Extensible {
String name: null, String name: null,
String namespace: null}) { String namespace: null}) {
final route = final route =
root.child(path, handlers: middleware, method: method, name: name); root.child(path, handlers: middleware, method: method, name: name);
final router = new Router(root: route); final router = new Router(root: route);
callback(router); callback(router);
@ -164,7 +178,7 @@ class Router extends Extensible {
Map copiedMiddleware = new Map.from(router.requestMiddleware); Map copiedMiddleware = new Map.from(router.requestMiddleware);
for (String middlewareName in copiedMiddleware.keys) { for (String middlewareName in copiedMiddleware.keys) {
requestMiddleware["$middlewarePrefix$middlewareName"] = requestMiddleware["$middlewarePrefix$middlewareName"] =
copiedMiddleware[middlewareName]; copiedMiddleware[middlewareName];
} }
return route; return route;
@ -179,9 +193,130 @@ class Router extends Extensible {
/// ///
/// You can pass an additional filter to determine which /// You can pass an additional filter to determine which
/// routes count as matches. /// routes count as matches.
Route resolve(String path, [bool filter(Route route)]) => Route resolveOnRoot(String path, {bool filter(Route route)}) =>
root.resolve(path, filter: filter); root.resolve(path, filter: filter);
/// Finds the first [Route] that matches the given path,
/// with the given method.
Route resolve(String path, {String method: 'GET'}) {
final String _path = path.replaceAll(_straySlashes, '');
final segments = _path.split('/').where((str) => str.isNotEmpty);
_printDebug('Segments: $segments');
return _resolve(root, _path, method, segments.first, segments.skip(1));
}
_validHead(RegExp rgx) {
return !rgx.hasMatch('');
}
_resolve(Route ref, String fullPath, String method, String head,
Iterable<String> tail) {
_printDebug(
'$method on $ref: path: $fullPath, head: $head, tail: ${tail.join(
'/')}');
// Does the index route match?
if (ref.matcher.hasMatch(fullPath)) {
final index = ref.indexRoute;
for (Route child in ref.allIndices) {
_printDebug('Possible index: $child');
if (child == child.indexRoute && ['*', method].contains(child.method)) {
_printDebug('Possible index was exact match: $child');
return child;
}
final resolved = _resolve(child, fullPath, method, head, tail);
if (resolved != null) {
_printDebug('Resolved from possible index: $resolved');
return resolved;
} else
_printDebug('Possible index returned null: $child');
}
if (['*', method].contains(index.method)) {
return index;
}
} else {
// Try to match children by full path
for (Route child in ref.children) {
if (child.matcher.hasMatch(fullPath)) {
final resolved = _resolve(child, fullPath, method, head, tail);
if (resolved != null) {
return resolved;
}
}
}
// Now, let's check if any route's head matches the
// given head. If so, we try to resolve with that
// route, using a head corresponding to the one we
// matched.
for (Route child in ref.children) {
if (child._head != null &&
child._head.hasMatch(fullPath) &&
_validHead(child._head)) {
final newHead = child._head
.firstMatch(fullPath)
.group(0)
.replaceAll(_straySlashes, '');
final newTail = fullPath
.replaceAll(child._head, '')
.replaceAll(_straySlashes, '')
.split('/')
.where((str) => str.isNotEmpty);
final resolved = _resolve(child, fullPath, method, newHead, newTail);
if (resolved != null) {
_printDebug(
'Head match: $resolved from head: ${child._head.pattern}');
return resolved;
}
} else if (child._head != null) {
_printDebug(
'Head ${child._head
.pattern} on $child failed to match $fullPath');
}
}
}
if (tail.isEmpty)
return null;
else {
return _resolve(
ref, fullPath, method, head + '/' + tail.first, tail.skip(1));
}
}
/// Returns a new Router in which the route tree has been
/// flattened into a linear list.
Router flatten() {
final router = new Router();
_flatten(Route route) {
// if (route.children.isNotEmpty && route.method == '*') return;
final r = new Route._base();
r
.._handlers.addAll(route.handlerSequence)
.._head = route._head
.._matcher = route.matcher
.._method = route.method
.._parent = router.root
.._path = route.path;
router.root._children.add(r);
route.children.forEach(_flatten);
}
root._children.forEach(_flatten);
return router..debug = debug;
}
/// Incorporates another [Router]'s routes into this one's. /// Incorporates another [Router]'s routes into this one's.
/// ///
/// If `hooked` is set to `true` and a [Service] is provided, /// If `hooked` is set to `true` and a [Service] is provided,
@ -200,10 +335,67 @@ class Router extends Extensible {
Map copiedMiddleware = new Map.from(router.requestMiddleware); Map copiedMiddleware = new Map.from(router.requestMiddleware);
for (String middlewareName in copiedMiddleware.keys) { for (String middlewareName in copiedMiddleware.keys) {
requestMiddleware["$middlewarePrefix$middlewareName"] = requestMiddleware["$middlewarePrefix$middlewareName"] =
copiedMiddleware[middlewareName]; copiedMiddleware[middlewareName];
} }
root.child(path, debug: debug).addChild(router.root); // final route = root.addChild(router.root, join: false);
final route = root.child(path, debug: debug).addChild(router.root);
route.debug = debug;
if (path is! RegExp) {
final _path = path.toString().replaceAll(_straySlashes, '');
_migrateRoute(Route r) {
r._path = '$_path/${r.path}'.replaceAll(_straySlashes, '');
var stripped = r.matcher.pattern
.replaceAll(_rgxStart, '')
.replaceAll(_rgxEnd, '')
.replaceAll(_rgxStraySlashes, '')
.replaceAll(_straySlashes, '');
stripped = '$_path/$stripped'.replaceAll(_straySlashes, '');
r._matcher = new RegExp('^$stripped\$');
if (r._head != null) {
final head = r._head.pattern
.replaceAll(_rgxStart, '')
.replaceAll(_rgxEnd, '')
.replaceAll(_rgxStraySlashes, '')
.replaceAll('\\/', '/')
.replaceAll(_straySlashes, '');
r._head = new RegExp(_matcherify('$_path/$head').replaceAll(_rgxEnd, ''));
_printDebug('Head of migrated route: ${r._head.pattern}');
}
r.children.forEach(_migrateRoute);
}
route.children.forEach(_migrateRoute);
}
}
/// Removes empty routes that could complicate route resolution.
void normalize() {
_printDebug('Normalizing route tree...');
_normalize(Route route) {
route.children.forEach(_normalize);
if (route.path
.replaceAll(_straySlashes, '')
.isEmpty &&
route.children.isNotEmpty) {
_printDebug('Erasing this route: $route');
route.parent._handlers.addAll(route.handlers);
for (Route child in route.children) {
route.parent._children.add(child.._parent = route.parent);
}
route.parent._children.remove(route);
}
}
root.children.forEach(_normalize);
} }
/// Adds a route that responds to any request matching the given path. /// Adds a route that responds to any request matching the given path.
@ -248,7 +440,7 @@ class Router extends Extensible {
} }
class _RootRoute extends Route { class _RootRoute extends Route {
_RootRoute() : super("/", name: "<root>"); _RootRoute() : super("/", method: '*', name: "<root>");
@override @override
String toString() => "ROOT"; String toString() => "ROOT";

View file

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

View file

@ -1,10 +0,0 @@
import 'package:test/test.dart';
import 'route/all_tests.dart' as route;
import 'router/all_tests.dart' as router;
import 'server/all_tests.dart' as server;
main() {
group('route', route.main);
group('router', router.main);
group('server', server.main);
}

View file

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Tests</title>
</head>
<body>
<script src="all_tests.browser.dart" type="application/dart"></script>
<script src="packages/browser/dart.js"></script>
</body>
</html>

123
test/method/all_tests.dart Normal file
View file

@ -0,0 +1,123 @@
import 'package:angel_route/angel_route.dart';
import 'package:test/test.dart';
main() {
var router = new Router(debug: true);
final getFoo = router.get('/foo', 'GET');
final postFoo = router.post('/foo', 'POST');
Route getFooBar, postFooBar, patchFooBarId;
router.group('/foo/bar', (router) {
getFooBar = router.get('/', 'GET');
postFooBar = router.post('/', 'POST');
patchFooBarId = router.patch('/:id([0-9]+)', 'PATCH');
});
final Router books = new Router();
final getBooks = books.get('/', 'GET');
final postBooks = books.post('/', 'POST');
final getBooksFoo = books.get('/foo', 'GET');
final postBooksFoo = books.post('/foo', 'POST');
Route getBooksChapters,
postBooksChapters,
getBooksChaptersReviews,
postBooksChaptersReviews;
books.group('/:id/chapters', (router) {
getBooksChapters = router.get('/', 'GET');
postBooksChapters = router.post('/', 'POST');
router.group('/:id([A-Za-z]+)/reviews', (router) {
getBooksChaptersReviews = router.get('/', 'GET');
postBooksChaptersReviews = router.post('/', 'POST');
});
});
router.mount('/books', books);
router.normalize();
group('top level', () {
test('get', () => expect(router.resolve('/foo'), equals(getFoo)));
test('post', () {
router.dumpTree();
expect(router.resolve('/foo', method: 'POST'), equals(postFoo));
});
});
group('group', () {
test('get', () {
expect(router.resolve('/foo/bar'), equals(getFooBar));
});
test('post', () {
expect(router.resolve('/foo/bar', method: 'POST'), equals(postFooBar));
});
test('patch+id', () {
router.dumpTree();
expect(
router.resolve('/foo/bar/2', method: 'PATCH'), equals(patchFooBarId));
});
test('404', () {
expect(router.resolve('/foo/bar/A', method: 'PATCH'), isNull);
});
});
group('mount', () {
group('no params', () {
test('get', () {
expect(router.resolve('/books'), equals(getBooks));
expect(router.resolve('/books/foo'), equals(getBooksFoo));
});
test('post', () {
expect(router.resolve('/books', method: 'POST'), equals(postBooks));
expect(
router.resolve('/books/foo', method: 'POST'), equals(postBooksFoo));
});
});
group('with params', () {
test('1 param', () {
expect(router.resolve('/books/abc/chapters'), equals(getBooksChapters));
expect(router.resolve('/books/abc/chapters', method: 'POST'),
equals(postBooksChapters));
});
group('2 params', () {
setUp(router.dumpTree);
test('get', () {
expect(router.resolve('/books/abc/chapters/ABC/reviews'),
equals(getBooksChaptersReviews));
});
test('post', () {
expect(
router.resolve('/books/abc/chapters/ABC/reviews', method: 'POST'),
equals(postBooksChaptersReviews));
});
test('404', () {
expect(router.resolve('/books/abc/chapters/1'), isNull);
expect(router.resolve('/books/abc/chapters/12'), isNull);
expect(router.resolve('/books/abc/chapters/13.!'), isNull);
});
});
});
});
test('flatten', () {
router.dumpTree(header: 'BEFORE FLATTENING:');
final flat = router.flatten();
for (Route route in flat.root.children) {
print('${route.method} ${route.path} => ${route.matcher.pattern}');
}
});
}

View file

@ -1 +0,0 @@
../packages

View file

@ -1 +0,0 @@
../../packages

View file

@ -1,7 +1,6 @@
import 'package:angel_route/angel_route.dart'; import 'package:angel_route/angel_route.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'fallback.dart' as fallback; import 'fallback.dart' as fallback;
import 'use.dart' as use;
final ABC = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; final ABC = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
@ -13,7 +12,8 @@ main() {
router.delete('/user/:id/detail', (id) => num.parse(id)); router.delete('/user/:id/detail', (id) => num.parse(id));
Route lower; Route lower;
final letters = router.group('/letter///', (router) {
router.group('/letter///', (router) {
lower = router lower = router
.get('/:id([A-Za-z])', (id) => ABC.indexOf(id[0])) .get('/:id([A-Za-z])', (id) => ABC.indexOf(id[0]))
.child('////lower', handlers: [(String id) => id.toLowerCase()[0]]); .child('////lower', handlers: [(String id) => id.toLowerCase()[0]]);
@ -30,7 +30,6 @@ main() {
}); });
group('fallback', fallback.main); group('fallback', fallback.main);
test('group & use', use.main);
test('hierarchy', () { test('hierarchy', () {
expect(lower.absoluteParent, equals(router.root)); expect(lower.absoluteParent, equals(router.root));
@ -41,10 +40,10 @@ main() {
}); });
test('resolve', () { test('resolve', () {
expect(router.resolve('/'), equals(indexRoute)); expect(router.resolveOnRoot('/'), equals(indexRoute));
expect(router.resolve('user/1337/detail'), equals(deleteUserById)); expect(router.resolveOnRoot('user/1337/detail'), equals(deleteUserById));
expect(router.resolve('/user/1337/detail'), equals(deleteUserById)); expect(router.resolveOnRoot('/user/1337/detail'), equals(deleteUserById));
expect(router.resolve('letter/a/lower'), equals(lower)); expect(router.resolveOnRoot('letter/a/lower'), equals(lower));
expect(router.resolve('letter/2/lower'), isNull); expect(router.resolveOnRoot('letter/2/lower'), isNull);
}); });
} }

View file

@ -13,8 +13,8 @@ main() {
final fallback = router.get('*', () => 'fallback'); final fallback = router.get('*', () => 'fallback');
test('resolve', () { test('resolve', () {
expect(router.resolve('/foo'), equals(fallback)); expect(router.resolveOnRoot('/foo'), equals(fallback));
expect(router.resolve('/user/:id'), equals(userById)); expect(router.resolveOnRoot('/user/:id'), equals(userById));
expect(router.resolve('/user/:id', checkPost), isNull); expect(router.resolveOnRoot('/user/:id', filter: checkPost), isNull);
}); });
} }

View file

@ -1 +0,0 @@
../../packages

View file

@ -22,7 +22,7 @@ main() {
url = 'http://${server.address.address}:${server.port}'; url = 'http://${server.address.address}:${server.port}';
server.listen((request) async { server.listen((request) async {
final resolved = router.resolve(request.uri.toString(), (route) { final resolved = router.resolveOnRoot(request.uri.toString(), filter: (route) {
print( print(
'$route matches ${request.method} ${request.uri}? ${route.method == request.method || route.method == '*'}'); '$route matches ${request.method} ${request.uri}? ${route.method == request.method || route.method == '*'}');
return route.method == request.method || route.method == '*'; return route.method == request.method || route.method == '*';

View file

@ -1 +0,0 @@
../../packages

View file

@ -22,14 +22,14 @@ main() {
group('no params', () { group('no params', () {
test('resolve', () { test('resolve', () {
expect(child.resolve('a'), equals(a)); expect(child.resolveOnRoot('a'), equals(a));
expect(child.resolve('b'), equals(b)); expect(child.resolveOnRoot('b'), equals(b));
expect(child.resolve('b/c'), equals(c)); expect(child.resolveOnRoot('b/c'), equals(c));
expect(parent.resolve('child/a'), equals(a)); expect(parent.resolveOnRoot('child/a'), equals(a));
expect(parent.resolve('a'), isNull); expect(parent.resolveOnRoot('a'), isNull);
expect(parent.resolve('child/b'), equals(b)); expect(parent.resolveOnRoot('child/b'), equals(b));
expect(parent.resolve('child/b/c'), equals(c)); expect(parent.resolveOnRoot('child/b/c'), equals(c));
}); });
}); });
} }

View file

@ -1 +0,0 @@
../../packages

View file

@ -1 +0,0 @@
../packages

View file

@ -1 +0,0 @@
../../packages

View file

@ -1 +0,0 @@
../../packages