Bump to 3.0.0

This commit is contained in:
Tobe O 2018-08-20 14:59:51 -04:00
parent 951c593d58
commit 6142f49724
15 changed files with 154 additions and 170 deletions

View file

@ -2,6 +2,7 @@
<configuration default="false" name="All Tests" type="DartTestRunConfigurationType" factoryName="Dart Test" singleton="true">
<option name="filePath" value="$PROJECT_DIR$/test" />
<option name="scope" value="FOLDER" />
<option name="testRunnerOptions" value="-j4" />
<method />
</configuration>
</component>

View file

@ -0,0 +1,8 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="parse in parse_test.dart" type="DartTestRunConfigurationType" factoryName="Dart Test" singleton="true" nameIsGenerated="true">
<option name="filePath" value="$PROJECT_DIR$/test/parse_test.dart" />
<option name="scope" value="GROUP_OR_TEST_BY_NAME" />
<option name="testName" value="parse" />
<method />
</configuration>
</component>

View file

@ -1,3 +1,8 @@
# 3.0.0-alpha
# 3.0.0
* Make `Router` and `Route` single-parameter generic.
* Remove `package:browser` dependency.
* `BrowserRouter.on` now only accepts a `String`.
* `MiddlewarePipeline.routingResults` now accepts
an `Iterable<RoutingResult>`, instead of just a `List`.
* Removed deprecated `Route.as`, as well as `Router.registerMiddleware`.
* Completely removed `Route.requestMiddleware`.

View file

@ -39,7 +39,7 @@ abstract class BrowserRouter extends Router {
void listen();
/// Identical to [all].
Route on(Pattern path, handler, {List middleware});
Route on(String path, handler, {List middleware});
}
abstract class _BrowserRouterImpl extends Router implements BrowserRouter {
@ -64,7 +64,7 @@ abstract class _BrowserRouterImpl extends Router implements BrowserRouter {
@override
void go(Iterable linkParams) => _goTo(navigate(linkParams));
Route on(Pattern path, handler, {List middleware}) =>
Route on(String path, handler, {List middleware}) =>
all(path, handler, middleware: middleware);
void prepareAnchors() {
@ -176,7 +176,7 @@ class _PushStateRouter extends _BrowserRouterImpl {
void handleState(state) {
if (state is Map && state.containsKey('path')) {
var path = state['path'];
var path = state['path'].toString();
final resolved = resolveAbsolute(path).first;
if (resolved != null && resolved.route != _current) {

View file

@ -2,13 +2,13 @@ part of angel_route.src.router;
class RouteGrammar {
static final Parser<String> notSlash =
match(new RegExp(r'[^/]+')).value((r) => r.span.text);
match<String>(new RegExp(r'[^/]+')).value((r) => r.span.text);
static final Parser<RegExp> regExp = match<RegExp>(new RegExp(r'\((.+)\)'))
.value((r) => new RegExp(r.scanner.lastMatch[1]));
static final Parser<String> parameterName =
match(new RegExp(r':([A-Za-z0-9_]+)'))
match<String>(new RegExp(r':([A-Za-z0-9_]+)'))
.value((r) => r.span.text.substring(1));
static final Parser<ParameterSegment> parameterSegment = chain([
@ -16,7 +16,7 @@ class RouteGrammar {
match('?').value((r) => true).opt(),
regExp.opt(),
]).map((r) {
var s = new ParameterSegment(r.value[0], r.value[2]);
var s = new ParameterSegment(r.value[0] as String, r.value[2] as RegExp);
return r.value[1] == true ? new OptionalSegment(s) : s;
});
@ -26,16 +26,17 @@ class RouteGrammar {
.map((r) => r.span.text),
parameterSegment,
]).map((r) {
return new ParsedParameterSegment(r.value[0], r.value[1]);
return new ParsedParameterSegment(
r.value[0] as String, r.value[1] as ParameterSegment);
});
static final Parser<WildcardSegment> wildcardSegment =
match('*').value((r) => new WildcardSegment());
match<WildcardSegment>('*').value((r) => new WildcardSegment());
static final Parser<ConstantSegment> constantSegment =
notSlash.map((r) => new ConstantSegment(r.value));
notSlash.map<ConstantSegment>((r) => new ConstantSegment(r.value));
static final Parser<RouteSegment> routeSegment = any([
static final Parser<RouteSegment> routeSegment = any<RouteSegment>([
parsedParameterSegment,
parameterSegment,
wildcardSegment,
@ -62,7 +63,8 @@ class RouteDefinition {
if (out == null)
out = s.compile(isLast);
else
out = s.compileNext(out.then(match('/')).index(0), isLast);
out = s.compileNext(
out.then(match('/')).index(0).cast<Map<String, dynamic>>(), isLast);
}
return out;
@ -88,13 +90,13 @@ class ConstantSegment extends RouteSegment {
@override
Parser<Map<String, dynamic>> compile(bool isLast) {
return match(text).value((r) => {});
return match<Map<String, dynamic>>(text).value((r) => <String, dynamic>{});
}
@override
Parser<Map<String, dynamic>> compileNext(
Parser<Map<String, dynamic>> p, bool isLast) {
return p.then(compile(isLast)).index(0);
return p.then(compile(isLast)).index(0).cast<Map<String, dynamic>>();
}
}
@ -117,7 +119,7 @@ class WildcardSegment extends RouteSegment {
@override
Parser<Map<String, dynamic>> compileNext(
Parser<Map<String, dynamic>> p, bool isLast) {
return p.then(_compile(isLast)).index(0);
return p.then(_compile(isLast)).index(0).cast<Map<String, dynamic>>();
}
}
@ -140,8 +142,9 @@ class OptionalSegment extends ParameterSegment {
Parser<Map<String, dynamic>> compileNext(
Parser<Map<String, dynamic>> p, bool isLast) {
return p.then(_compile().opt()).map((r) {
if (r.value[1] == null) return r.value[0];
return r.value[0]..addAll({name: Uri.decodeComponent(r.value[1])});
if (r.value[1] == null) return r.value[0] as Map<String, dynamic>;
return (r.value[0] as Map<String, dynamic>)
..addAll({name: Uri.decodeComponent(r.value[1] as String)});
});
}
}
@ -158,22 +161,24 @@ class ParameterSegment extends RouteSegment {
return 'Param: $name';
}
Parser<Map<String, dynamic>> _compile() {
Parser<String> _compile() {
return regExp != null
? match(regExp).value((r) => r.span.text)
? match<String>(regExp).value((r) => r.span.text)
: RouteGrammar.notSlash;
}
@override
Parser<Map<String, dynamic>> compile(bool isLast) {
return _compile().map((r) => {name: Uri.decodeComponent(r.span.text)});
return _compile().map<Map<String, dynamic>>(
(r) => {name: Uri.decodeComponent(r.span.text)});
}
@override
Parser<Map<String, dynamic>> compileNext(
Parser<Map<String, dynamic>> p, bool isLast) {
return p.then(_compile()).map((r) {
return r.value[0]..addAll({name: Uri.decodeComponent(r.value[1])});
return (r.value[0] as Map<String, dynamic>)
..addAll({name: Uri.decodeComponent(r.value[1] as String)});
});
}
}
@ -205,8 +210,10 @@ class ParsedParameterSegment extends RouteSegment {
Parser<Map<String, dynamic>> compileNext(
Parser<Map<String, dynamic>> p, bool isLast) {
return p.then(parameter._compile()).map((r) {
return r.value[0]
..addAll({parameter.name: getValue(Uri.decodeComponent(r.value[1]))});
return (r.value[0] as Map<String, dynamic>)
..addAll({
parameter.name: getValue(Uri.decodeComponent(r.value[1] as String))
});
});
}
}

View file

@ -1,17 +1,17 @@
import 'router.dart';
/// A chain of arbitrary handlers obtained by routing a path.
class MiddlewarePipeline {
class MiddlewarePipeline<T> {
/// All the possible routes that matched the given path.
final List<RoutingResult> routingResults;
List _handlers;
final Iterable<RoutingResult<T>> routingResults;
List<T> _handlers;
/// An ordered list of every handler delegated to handle this request.
List get handlers {
List<T> get handlers {
if (_handlers != null) return _handlers;
final handlers = [];
final handlers = <T>[];
for (RoutingResult result in routingResults) {
for (var result in routingResults) {
handlers.addAll(result.allHandlers);
}

View file

@ -1,10 +1,10 @@
part of angel_route.src.router;
/// Represents a virtual location within an application.
class Route {
class Route<T> {
final String method;
final String path;
final List handlers;
final List<T> handlers;
final Map<String, Map<String, dynamic>> _cache = {};
final RouteDefinition _routeDefinition;
String name;
@ -14,10 +14,12 @@ class Route {
: _routeDefinition = RouteGrammar.routeDefinition
.parse(new SpanScanner(path.replaceAll(_straySlashes, '')))
.value {
if (_routeDefinition.segments.isEmpty) _parser = match('').value((r) => {});
if (_routeDefinition?.segments?.isNotEmpty != true)
_parser =
match<Map<String, dynamic>>('').value((r) => <String, dynamic>{});
}
factory Route.join(Route a, Route b) {
factory Route.join(Route<T> a, Route<T> b) {
var start = a.path.replaceAll(_straySlashes, '');
var end = b.path.replaceAll(_straySlashes, '');
return new Route('$start/$end'.replaceAll(_straySlashes, ''),
@ -27,23 +29,16 @@ class Route {
Parser<Map<String, dynamic>> get parser =>
_parser ??= _routeDefinition.compile();
@override
String toString() {
return '$method $path => $handlers';
}
Route clone() {
return new Route(path, method: method, handlers: handlers)
Route<T> clone() {
return new Route<T>(path, method: method, handlers: handlers)
.._cache.addAll(_cache);
}
/// Use the setter instead.
@deprecated
void as(String n) {
name = n;
}
String makeUri(Map<String, dynamic> params) {
var b = new StringBuffer();
int i = 0;

View file

@ -3,42 +3,46 @@ library angel_route.src.router;
import 'package:combinator/combinator.dart';
import 'package:meta/meta.dart';
import 'package:string_scanner/string_scanner.dart';
import 'routing_exception.dart';
import '../string_util.dart';
import 'routing_exception.dart';
part 'grammar.dart';
part 'symlink_route.dart';
part 'route.dart';
part 'routing_result.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'/+\$');
part 'symlink_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'(^/+)|(/+$)');
/// An abstraction over complex [Route] trees. Use this instead of the raw API. :)
class Router {
class Router<T> {
final Map<String, Iterable<RoutingResult>> _cache = {};
//final List<_ChainedRouter> _chained = [];
final List _middleware = [];
final Map<Pattern, Router> _mounted = {};
final List<Route> _routes = [];
final List<T> _middleware = [];
final Map<Pattern, Router<T>> _mounted = {};
final List<Route<T>> _routes = [];
bool _useCache = false;
List get middleware => new List.unmodifiable(_middleware);
List<T> get middleware => new List<T>.unmodifiable(_middleware);
Map<Pattern, Router> get mounted =>
new Map<Pattern, Router>.unmodifiable(_mounted);
/// Additional filters to be run on designated requests.
Map<String, dynamic> requestMiddleware = {};
List<Route> get routes {
return _routes.fold<List<Route>>([], (out, route) {
if (route is SymlinkRoute) {
var childRoutes = route.router.routes.fold<List<Route>>([], (out, r) {
List<Route<T>> get routes {
return _routes.fold<List<Route<T>>>([], (out, route) {
if (route is SymlinkRoute<T>) {
var childRoutes =
route.router.routes.fold<List<Route<T>>>([], (out, r) {
return out
..add(
route.path.isEmpty ? r : new Route.join(route, r),
@ -64,46 +68,44 @@ class Router {
/// Adds a route that responds to the given path
/// for requests with the given method (case-insensitive).
/// Provide '*' as the method to respond to all methods.
Route addRoute(String method, String path, Object handler,
{List middleware: const []}) {
Route<T> addRoute(String method, String path, T handler,
{Iterable<T> middleware: const []}) {
if (_useCache == true)
throw new StateError('Cannot add routes after caching is enabled.');
// Check if any mounted routers can match this
final handlers = [handler];
final handlers = <T>[handler];
if (middleware != null) handlers.insertAll(0, middleware);
final route = new Route(path, method: method, handlers: handlers);
final route = new Route<T>(path, method: method, handlers: handlers);
_routes.add(route);
return route;
}
/// Prepends the given middleware to any routes created
/// Prepends the given [middleware] to any routes created
/// by the resulting router.
///
/// [middleware] can be either an `Iterable`, or a single object.
///
/// The resulting router can be chained, too.
_ChainedRouter chain(middleware) {
var piped = new _ChainedRouter(this, middleware);
var route = new SymlinkRoute('/', piped);
_ChainedRouter<T> chain(Iterable<T> middleware) {
var piped = new _ChainedRouter<T>(this, middleware);
var route = new SymlinkRoute<T>('/', piped);
_routes.add(route);
return piped;
}
/// Returns a [Router] with a duplicated version of this tree.
Router clone() {
final router = new Router();
final newMounted = new Map<Pattern, Router>.from(mounted);
Router<T> clone() {
final router = new Router<T>();
final newMounted = new Map<Pattern, Router<T>>.from(mounted);
for (Route route in routes) {
if (route is! SymlinkRoute) {
for (var route in routes) {
if (route is! SymlinkRoute<T>) {
router._routes.add(route.clone());
} else if (route is SymlinkRoute) {
} else if (route is SymlinkRoute<T>) {
final newRouter = route.router.clone();
newMounted[route.path] = newRouter;
final symlink = new SymlinkRoute(route.path, newRouter);
final symlink = new SymlinkRoute<T>(route.path, newRouter);
router._routes.add(symlink);
}
}
@ -161,13 +163,11 @@ class Router {
///
/// Returns the created route.
/// You can also register middleware within the router.
SymlinkRoute group(String path, void callback(Router router),
{Iterable middleware: const [],
String name: null,
String namespace: null}) {
final router = new Router().._middleware.addAll(middleware);
SymlinkRoute<T> group(String path, void callback(Router router),
{Iterable<T> middleware: const [], String name: null}) {
final router = new Router<T>().._middleware.addAll(middleware);
callback(router);
return mount(path, router, namespace: namespace)..name = name;
return mount(path, router)..name = name;
}
/// Generates a URI string based on the given input.
@ -265,12 +265,6 @@ class Router {
: segments.join('/');
}
/// Manually assign via [requestMiddleware] instead.
@deprecated
registerMiddleware(String name, middleware) {
requestMiddleware[name] = middleware;
}
/// Finds the first [Route] that matches the given path,
/// with the given method.
bool resolve(String absolute, String relative, List<RoutingResult> out,
@ -344,122 +338,97 @@ class Router {
}
/// Incorporates another [Router]'s routes into this one's.
///
/// If `hooked` is set to `true` and a [Service] is provided,
/// then that service will be wired to a [HookedService] proxy.
/// If a `namespace` is provided, then any middleware
/// from the provided [Router] will be prefixed by that namespace,
/// with a dot.
/// For example, if the [Router] has a middleware 'y', and the `namespace`
/// is 'x', then that middleware will be available as 'x.y' in the main router.
/// These namespaces can be nested.
SymlinkRoute mount(String path, Router router,
{bool hooked: true, String namespace: null}) {
// Let's copy middleware, heeding the optional middleware namespace.
String middlewarePrefix = namespace != null ? "$namespace." : "";
Map copiedMiddleware = new Map.from(router.requestMiddleware);
for (String middlewareName in copiedMiddleware.keys) {
requestMiddleware["$middlewarePrefix$middlewareName"] =
copiedMiddleware[middlewareName];
}
final route = new SymlinkRoute(path, router);
SymlinkRoute<T> mount(String path, Router<T> router) {
final route = new SymlinkRoute<T>(path, router);
_mounted[route.path] = router;
_routes.add(route);
//route._head = new RegExp(route.matcher.pattern.replaceAll(_rgxEnd, ''));
return route..name = namespace;
return route;
}
/// Adds a route that responds to any request matching the given path.
Route all(String path, Object handler, {List middleware}) {
Route<T> all(String path, T handler, {Iterable<T> middleware}) {
return addRoute('*', path, handler, middleware: middleware);
}
/// Adds a route that responds to a DELETE request.
Route delete(String path, Object handler, {List middleware}) {
Route<T> delete(String path, T handler, {Iterable<T> middleware}) {
return addRoute('DELETE', path, handler, middleware: middleware);
}
/// Adds a route that responds to a GET request.
Route get(String path, Object handler, {List middleware}) {
Route<T> get(String path, T handler, {Iterable<T> middleware}) {
return addRoute('GET', path, handler, middleware: middleware);
}
/// Adds a route that responds to a HEAD request.
Route head(String path, Object handler, {List middleware}) {
Route<T> head(String path, T handler, {Iterable<T> middleware}) {
return addRoute('HEAD', path, handler, middleware: middleware);
}
/// Adds a route that responds to a OPTIONS request.
Route options(String path, Object handler, {List middleware}) {
Route<T> options(String path, T handler, {Iterable<T> middleware}) {
return addRoute('OPTIONS', path, handler, middleware: middleware);
}
/// Adds a route that responds to a POST request.
Route post(String path, Object handler, {List middleware}) {
Route<T> post(String path, T handler, {Iterable<T> middleware}) {
return addRoute('POST', path, handler, middleware: middleware);
}
/// Adds a route that responds to a PATCH request.
Route patch(String path, Object handler, {List middleware}) {
Route<T> patch(String path, T handler, {Iterable<T> middleware}) {
return addRoute('PATCH', path, handler, middleware: middleware);
}
/// Adds a route that responds to a PUT request.
Route put(String path, Object handler, {List middleware}) {
Route put(String path, T handler, {Iterable<T> middleware}) {
return addRoute('PUT', path, handler, middleware: middleware);
}
}
class _ChainedRouter extends Router {
final List _handlers = [];
class _ChainedRouter<T> extends Router<T> {
final List<T> _handlers = <T>[];
Router _root;
_ChainedRouter.empty();
_ChainedRouter(Router root, middleware) {
_ChainedRouter(Router root, Iterable<T> middleware) {
this._root = root;
_handlers.addAll(middleware is Iterable ? middleware : [middleware]);
_handlers.addAll(middleware);
}
@override
Route addRoute(String method, String path, handler,
{List middleware: const []}) {
Route<T> addRoute(String method, String path, handler,
{Iterable<T> middleware: const []}) {
var route = super.addRoute(method, path, handler,
middleware: []..addAll(_handlers)..addAll(middleware ?? []));
//_root._routes.add(route);
return route;
}
SymlinkRoute group(String path, void callback(Router router),
{Iterable middleware: const [],
String name: null,
String namespace: null}) {
SymlinkRoute<T> group(String path, void callback(Router<T> router),
{Iterable<T> middleware: const [], String name: null}) {
final router =
new _ChainedRouter(_root, []..addAll(_handlers)..addAll(middleware));
new _ChainedRouter<T>(_root, []..addAll(_handlers)..addAll(middleware));
callback(router);
return mount(path, router, namespace: namespace)..name = name;
return mount(path, router)..name = name;
}
@override
SymlinkRoute mount(String path, Router router,
{bool hooked: true, String namespace: null}) {
final route =
super.mount(path, router, hooked: hooked, namespace: namespace);
SymlinkRoute<T> mount(String path, Router<T> router) {
final route = super.mount(path, router);
route.router._middleware.insertAll(0, _handlers);
//_root._routes.add(route);
return route;
}
@override
_ChainedRouter chain(middleware) {
final piped = new _ChainedRouter.empty().._root = _root;
piped._handlers.addAll([]
..addAll(_handlers)
..addAll(middleware is Iterable ? middleware : [middleware]));
var route = new SymlinkRoute('/', piped);
_ChainedRouter<T> chain(Iterable<T> middleware) {
final piped = new _ChainedRouter<T>.empty().._root = _root;
piped._handlers.addAll([]..addAll(_handlers)..addAll(middleware));
var route = new SymlinkRoute<T>('/', piped);
_routes.add(route);
return piped;
}
@ -467,14 +436,12 @@ class _ChainedRouter extends Router {
/// Optimizes a router by condensing all its routes into one level.
Router flatten(Router router) {
var flattened = new Router()
..requestMiddleware.addAll(router.requestMiddleware);
var flattened = new Router();
for (var route in router.routes) {
if (route is SymlinkRoute) {
var base = route.path.replaceAll(_straySlashes, '');
var child = flatten(route.router);
flattened.requestMiddleware.addAll(child.requestMiddleware);
for (var route in child.routes) {
var path = route.path.replaceAll(_straySlashes, '');

View file

@ -1,12 +1,12 @@
part of angel_route.src.router;
/// Represents a complex result of navigating to a path.
class RoutingResult {
class RoutingResult<T> {
/// The parse result that matched the given sub-path.
final ParseResult<Map<String, dynamic>> parseResult;
/// A nested instance, if a sub-path was matched.
final Iterable<RoutingResult> nested;
final Iterable<RoutingResult<T>> nested;
/// All route params matching this route on the current sub-path.
final Map<String, dynamic> params = {};
@ -14,18 +14,18 @@ class RoutingResult {
/// The [Route] that answered this sub-path.
///
/// This is mostly for internal use, and useless in production.
final Route shallowRoute;
final Route<T> shallowRoute;
/// The [Router] that answered this sub-path.
///
/// Only really for internal use.
final Router shallowRouter;
final Router<T> shallowRouter;
/// The remainder of the full path that was not matched, and was passed to [nested] routes.
final String tail;
/// The [RoutingResult] that matched the most specific sub-path.
RoutingResult get deepest {
RoutingResult<T> get deepest {
var search = this;
while (search?.nested?.isNotEmpty == true) search = search.nested.first;
@ -34,21 +34,21 @@ class RoutingResult {
}
/// The most specific route.
Route get route => deepest.shallowRoute;
Route<T> get route => deepest.shallowRoute;
/// The most specific router.
Router get router => deepest.shallowRouter;
Router<T> get router => deepest.shallowRouter;
/// The handlers at this sub-path.
List get handlers {
return []..addAll(shallowRouter.middleware)..addAll(shallowRoute.handlers);
List<T> get handlers {
return <T>[]..addAll(shallowRouter.middleware)..addAll(shallowRoute.handlers);
}
/// All handlers on this sub-path and its children.
List get allHandlers {
final handlers = [];
List<T> get allHandlers {
final handlers = <T>[];
void crawl(RoutingResult result) {
void crawl(RoutingResult<T> result) {
handlers.addAll(result.handlers);
if (result.nested?.isNotEmpty == true) {

View file

@ -2,7 +2,7 @@ part of angel_route.src.router;
/// Placeholder [Route] to serve as a symbolic link
/// to a mounted [Router].
class SymlinkRoute extends Route {
final Router router;
class SymlinkRoute<T> extends Route<T> {
final Router<T> router;
SymlinkRoute(String path, this.router) : super(path, method: null, handlers: null);
}

View file

@ -1,6 +1,6 @@
name: angel_route
description: A powerful, isomorphic routing library for Dart. It is mainly used in the Angel framework, but can be used in Flutter and on the Web.
version: 3.0.0-alpha
version: 3.0.0
author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/angel-dart/angel_route
environment:

View file

@ -2,9 +2,9 @@ import 'package:angel_route/angel_route.dart';
import 'package:test/test.dart';
main() {
var router = new Router()
..chain('a').group('/b', (router) {
router.chain('c').chain('d').group('/e', (router) {
var router = new Router<String>()
..chain(['a']).group('/b', (router) {
router.chain(['c']).chain(['d']).group('/e', (router) {
router.get('f', 'g');
});
})

View file

@ -9,7 +9,7 @@ main() {
router.get('/first/:first/last/:last', 'GET').name = 'full_name';
navigate(params) {
final uri = router.navigate(params);
final uri = router.navigate(params as Iterable);
print('Uri: $uri');
return uri;
}

View file

@ -9,7 +9,7 @@ void main() {
num getId(String path) {
var result = router.resolveAbsolute(path).first;
return result.allParams['id'];
return result.allParams['id'] as num;
}
test('parse', () {

View file

@ -1,5 +1,6 @@
import 'dart:convert';
import 'dart:io';
import 'package:angel_route/angel_route.dart';
import 'package:http/http.dart' as http;
import 'package:test/test.dart';
@ -76,7 +77,7 @@ main() {
client = new http.Client();
router.dumpTree();
server = await HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, 0);
server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
url = 'http://${server.address.address}:${server.port}';
server.listen((req) async {
@ -89,11 +90,11 @@ main() {
if (pipeline.handlers.isEmpty) {
res
..statusCode = HttpStatus.NOT_FOUND
..statusCode = 404
..writeln('404 Not Found');
} else {
for (final handler in pipeline.handlers) {
if (!await handler(req, res)) break;
if (!((await handler(req, res)) as bool)) break;
}
}