pkg:pedantic fixes
This commit is contained in:
parent
8a6cc0f15d
commit
745d75da67
20 changed files with 122 additions and 105 deletions
|
@ -36,7 +36,7 @@ a `Router` in itself.
|
||||||
```dart
|
```dart
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
final router = new Router();
|
final router = Router();
|
||||||
|
|
||||||
router.get('/users', () {});
|
router.get('/users', () {});
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ needs a lot of flexibility with which to handle requests.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
main() {
|
main() {
|
||||||
final router = new Router();
|
final router = Router();
|
||||||
|
|
||||||
router
|
router
|
||||||
.chain('middleware1')
|
.chain('middleware1')
|
||||||
|
@ -112,7 +112,7 @@ To prevent this for a given anchor, do any of the following:
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
main() {
|
main() {
|
||||||
final router = new BrowserRouter();
|
final router = BrowserRouter();
|
||||||
// ..
|
// ..
|
||||||
router.onRoute.listen((route) {
|
router.onRoute.listen((route) {
|
||||||
if (route == null)
|
if (route == null)
|
||||||
|
@ -133,7 +133,7 @@ Use [allParams](https://www.dartdocs.org/documentation/angel_route/1.0.3/angel_r
|
||||||
in a `RoutingResult` to get them as a nice `Map`:
|
in a `RoutingResult` to get them as a nice `Map`:
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
var router = new Router();
|
var router = Router();
|
||||||
router.get('/book/:id/authors', () => ...);
|
router.get('/book/:id/authors', () => ...);
|
||||||
|
|
||||||
var result = router.resolve('/book/foo/authors');
|
var result = router.resolve('/book/foo/authors');
|
||||||
|
|
|
@ -3,7 +3,7 @@ import 'dart:math';
|
||||||
import 'package:angel_route/angel_route.dart';
|
import 'package:angel_route/angel_route.dart';
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
final router = new Router();
|
final router = Router();
|
||||||
|
|
||||||
router.get('/whois/~:user', () {});
|
router.get('/whois/~:user', () {});
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ main() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
SomeQuery someQuery(id) => new SomeQuery();
|
SomeQuery someQuery(id) => SomeQuery();
|
||||||
|
|
||||||
class SomeQuery {
|
class SomeQuery {
|
||||||
List<SomeQueryReview> get reviews => [
|
List<SomeQueryReview> get reviews => [
|
||||||
|
|
|
@ -5,8 +5,8 @@ import 'package:path/path.dart' as p;
|
||||||
|
|
||||||
import 'angel_route.dart';
|
import 'angel_route.dart';
|
||||||
|
|
||||||
final RegExp _hash = new RegExp(r'^#/');
|
final RegExp _hash = RegExp(r'^#/');
|
||||||
final RegExp _straySlashes = new RegExp(r'(^/+)|(/+$)');
|
final RegExp _straySlashes = RegExp(r'(^/+)|(/+$)');
|
||||||
|
|
||||||
/// A variation of the [Router] support both hash routing and push state.
|
/// A variation of the [Router] support both hash routing and push state.
|
||||||
abstract class BrowserRouter<T> extends Router<T> {
|
abstract class BrowserRouter<T> extends Router<T> {
|
||||||
|
@ -20,8 +20,8 @@ abstract class BrowserRouter<T> extends Router<T> {
|
||||||
/// `listen` as `true` will call `listen` after initialization.
|
/// `listen` as `true` will call `listen` after initialization.
|
||||||
factory BrowserRouter({bool hash = false, bool listen = false}) {
|
factory BrowserRouter({bool hash = false, bool listen = false}) {
|
||||||
return hash
|
return hash
|
||||||
? new _HashRouter<T>(listen: listen)
|
? _HashRouter<T>(listen: listen)
|
||||||
: new _PushStateRouter<T>(listen: listen);
|
: _PushStateRouter<T>(listen: listen);
|
||||||
}
|
}
|
||||||
|
|
||||||
BrowserRouter._() : super();
|
BrowserRouter._() : super();
|
||||||
|
@ -49,8 +49,8 @@ abstract class _BrowserRouterImpl<T> extends Router<T>
|
||||||
bool _listening = false;
|
bool _listening = false;
|
||||||
Route _current;
|
Route _current;
|
||||||
StreamController<RoutingResult<T>> _onResolve =
|
StreamController<RoutingResult<T>> _onResolve =
|
||||||
new StreamController<RoutingResult<T>>();
|
StreamController<RoutingResult<T>>();
|
||||||
StreamController<Route<T>> _onRoute = new StreamController<Route<T>>();
|
StreamController<Route<T>> _onRoute = StreamController<Route<T>>();
|
||||||
|
|
||||||
Route get currentRoute => _current;
|
Route get currentRoute => _current;
|
||||||
|
|
||||||
|
@ -96,8 +96,8 @@ abstract class _BrowserRouterImpl<T> extends Router<T>
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void listen() {
|
void listen() {
|
||||||
if (_listening)
|
if (_listening) {
|
||||||
throw new StateError('The router is already listening for page changes.');
|
throw StateError('The router is already listening for page changes.');}
|
||||||
_listening = true;
|
_listening = true;
|
||||||
_listen();
|
_listen();
|
||||||
}
|
}
|
||||||
|
@ -153,10 +153,10 @@ class _PushStateRouter<T> extends _BrowserRouterImpl<T> {
|
||||||
_PushStateRouter({bool listen, Route root}) : super(listen: listen) {
|
_PushStateRouter({bool listen, Route root}) : super(listen: listen) {
|
||||||
var $base = window.document.querySelector('base[href]') as BaseElement;
|
var $base = window.document.querySelector('base[href]') as BaseElement;
|
||||||
|
|
||||||
if ($base?.href?.isNotEmpty != true)
|
if ($base?.href?.isNotEmpty != true) {
|
||||||
throw new StateError(
|
throw StateError(
|
||||||
'You must have a <base href="<base-url-here>"> element present in your document to run the push state router.');
|
'You must have a <base href="<base-url-here>"> element present in your document to run the push state router.');
|
||||||
_basePath = $base.href.replaceAll(_straySlashes, '');
|
} _basePath = $base.href.replaceAll(_straySlashes, '');
|
||||||
if (listen) this.listen();
|
if (listen) this.listen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,17 +2,17 @@ part of angel_route.src.router;
|
||||||
|
|
||||||
class RouteGrammar {
|
class RouteGrammar {
|
||||||
static const String notSlashRgx = r'([^/]+)';
|
static const String notSlashRgx = r'([^/]+)';
|
||||||
//static final RegExp rgx = new RegExp(r'\((.+)\)');
|
//static final RegExp rgx = RegExp(r'\((.+)\)');
|
||||||
static final Parser<String> notSlash =
|
static final Parser<String> notSlash =
|
||||||
match<String>(new RegExp(notSlashRgx)).value((r) => r.span.text);
|
match<String>(RegExp(notSlashRgx)).value((r) => r.span.text);
|
||||||
|
|
||||||
static final Parser<Match> regExp =
|
static final Parser<Match> regExp =
|
||||||
match<Match>(new RegExp(r'\(([^\n)]+)\)([^/]+)?'))
|
match<Match>(RegExp(r'\(([^\n)]+)\)([^/]+)?'))
|
||||||
.value((r) => r.scanner.lastMatch);
|
.value((r) => r.scanner.lastMatch);
|
||||||
|
|
||||||
static final Parser<Match> parameterName = match<Match>(
|
static final Parser<Match> parameterName =
|
||||||
new RegExp('$notSlashRgx?' r':([A-Za-z0-9_]+)' r'([^(/\n])?'))
|
match<Match>(RegExp('$notSlashRgx?' r':([A-Za-z0-9_]+)' r'([^(/\n])?'))
|
||||||
.value((r) => r.scanner.lastMatch);
|
.value((r) => r.scanner.lastMatch);
|
||||||
|
|
||||||
static final Parser<ParameterSegment> parameterSegment = chain([
|
static final Parser<ParameterSegment> parameterSegment = chain([
|
||||||
parameterName,
|
parameterName,
|
||||||
|
@ -40,17 +40,17 @@ class RouteGrammar {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var s = new ParameterSegment(match[2], rgx);
|
var s = ParameterSegment(match[2], rgx);
|
||||||
return r.value[1] == true ? new OptionalSegment(s) : s;
|
return r.value[1] == true ? OptionalSegment(s) : s;
|
||||||
});
|
});
|
||||||
|
|
||||||
static final Parser<ParsedParameterSegment> parsedParameterSegment = chain([
|
static final Parser<ParsedParameterSegment> parsedParameterSegment = chain([
|
||||||
match(new RegExp(r'(int|num|double)'),
|
match(RegExp(r'(int|num|double)'),
|
||||||
errorMessage: 'Expected "int","double", or "num".')
|
errorMessage: 'Expected "int","double", or "num".')
|
||||||
.map((r) => r.span.text),
|
.map((r) => r.span.text),
|
||||||
parameterSegment,
|
parameterSegment,
|
||||||
]).map((r) {
|
]).map((r) {
|
||||||
return new ParsedParameterSegment(
|
return ParsedParameterSegment(
|
||||||
r.value[0] as String, r.value[1] as ParameterSegment);
|
r.value[0] as String, r.value[1] as ParameterSegment);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -60,11 +60,11 @@ class RouteGrammar {
|
||||||
var m = r.scanner.lastMatch;
|
var m = r.scanner.lastMatch;
|
||||||
var pre = m[1] ?? '';
|
var pre = m[1] ?? '';
|
||||||
var post = m[2] ?? '';
|
var post = m[2] ?? '';
|
||||||
return new WildcardSegment(pre, post);
|
return WildcardSegment(pre, post);
|
||||||
});
|
});
|
||||||
|
|
||||||
static final Parser<ConstantSegment> constantSegment =
|
static final Parser<ConstantSegment> constantSegment =
|
||||||
notSlash.map<ConstantSegment>((r) => new ConstantSegment(r.value));
|
notSlash.map<ConstantSegment>((r) => ConstantSegment(r.value));
|
||||||
|
|
||||||
static final Parser<SlashSegment> slashSegment =
|
static final Parser<SlashSegment> slashSegment =
|
||||||
match(SlashSegment.rgx).map((_) => SlashSegment());
|
match(SlashSegment.rgx).map((_) => SlashSegment());
|
||||||
|
@ -79,14 +79,14 @@ class RouteGrammar {
|
||||||
|
|
||||||
// static final Parser<RouteDefinition> routeDefinition = routeSegment
|
// static final Parser<RouteDefinition> routeDefinition = routeSegment
|
||||||
// .star()
|
// .star()
|
||||||
// .map<RouteDefinition>((r) => new RouteDefinition(r.value ?? []))
|
// .map<RouteDefinition>((r) => RouteDefinition(r.value ?? []))
|
||||||
// .surroundedBy(match(RegExp(r'/*')).opt());
|
// .surroundedBy(match(RegExp(r'/*')).opt());
|
||||||
|
|
||||||
static final Parser slashes = match(RegExp(r'/*'));
|
static final Parser slashes = match(RegExp(r'/*'));
|
||||||
|
|
||||||
static final Parser<RouteDefinition> routeDefinition = routeSegment
|
static final Parser<RouteDefinition> routeDefinition = routeSegment
|
||||||
.separatedBy(slashes)
|
.separatedBy(slashes)
|
||||||
.map<RouteDefinition>((r) => new RouteDefinition(r.value ?? []))
|
.map<RouteDefinition>((r) => RouteDefinition(r.value ?? []))
|
||||||
.surroundedBy(slashes.opt());
|
.surroundedBy(slashes.opt());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,11 +101,12 @@ class RouteDefinition {
|
||||||
for (int i = 0; i < segments.length; i++) {
|
for (int i = 0; i < segments.length; i++) {
|
||||||
var s = segments[i];
|
var s = segments[i];
|
||||||
bool isLast = i == segments.length - 1;
|
bool isLast = i == segments.length - 1;
|
||||||
if (out == null)
|
if (out == null) {
|
||||||
out = s.compile(isLast);
|
out = s.compile(isLast);
|
||||||
else
|
} else {
|
||||||
out = s.compileNext(
|
out = s.compileNext(
|
||||||
out.then(match('/')).index(0).cast<RouteResult>(), isLast);
|
out.then(match('/')).index(0).cast<RouteResult>(), isLast);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
|
@ -175,8 +176,8 @@ class WildcardSegment extends RouteSegment {
|
||||||
|
|
||||||
RegExp _compile(bool isLast) {
|
RegExp _compile(bool isLast) {
|
||||||
return RegExp('$pre(${_symbol(isLast)})$post');
|
return RegExp('$pre(${_symbol(isLast)})$post');
|
||||||
// if (isLast) return match(new RegExp(r'.*'));
|
// if (isLast) return match(RegExp(r'.*'));
|
||||||
// return match(new RegExp(r'[^/]*'));
|
// return match(RegExp(r'[^/]*'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -12,16 +12,17 @@ class Route<T> {
|
||||||
|
|
||||||
Route(this.path, {@required this.method, @required this.handlers})
|
Route(this.path, {@required this.method, @required this.handlers})
|
||||||
: _routeDefinition = RouteGrammar.routeDefinition
|
: _routeDefinition = RouteGrammar.routeDefinition
|
||||||
.parse(new SpanScanner(path.replaceAll(_straySlashes, '')))
|
.parse(SpanScanner(path.replaceAll(_straySlashes, '')))
|
||||||
.value {
|
.value {
|
||||||
if (_routeDefinition?.segments?.isNotEmpty != true)
|
if (_routeDefinition?.segments?.isNotEmpty != true) {
|
||||||
_parser = match('').map((r) => RouteResult({}));
|
_parser = match('').map((r) => RouteResult({}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
factory Route.join(Route<T> a, Route<T> b) {
|
factory Route.join(Route<T> a, Route<T> b) {
|
||||||
var start = a.path.replaceAll(_straySlashes, '');
|
var start = a.path.replaceAll(_straySlashes, '');
|
||||||
var end = b.path.replaceAll(_straySlashes, '');
|
var end = b.path.replaceAll(_straySlashes, '');
|
||||||
return new Route('$start/$end'.replaceAll(_straySlashes, ''),
|
return Route('$start/$end'.replaceAll(_straySlashes, ''),
|
||||||
method: b.method, handlers: b.handlers);
|
method: b.method, handlers: b.handlers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,21 +34,22 @@ class Route<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Route<T> clone() {
|
Route<T> clone() {
|
||||||
return new Route<T>(path, method: method, handlers: handlers)
|
return Route<T>(path, method: method, handlers: handlers)
|
||||||
.._cache.addAll(_cache);
|
.._cache.addAll(_cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
String makeUri(Map<String, dynamic> params) {
|
String makeUri(Map<String, dynamic> params) {
|
||||||
var b = new StringBuffer();
|
var b = StringBuffer();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
for (var seg in _routeDefinition.segments) {
|
for (var seg in _routeDefinition.segments) {
|
||||||
if (i++ > 0) b.write('/');
|
if (i++ > 0) b.write('/');
|
||||||
if (seg is ConstantSegment)
|
if (seg is ConstantSegment) {
|
||||||
b.write(seg.text);
|
b.write(seg.text);
|
||||||
else if (seg is ParameterSegment) {
|
} else if (seg is ParameterSegment) {
|
||||||
if (!params.containsKey(seg.name))
|
if (!params.containsKey(seg.name)) {
|
||||||
throw new ArgumentError('Missing parameter "${seg.name}".');
|
throw ArgumentError('Missing parameter "${seg.name}".');
|
||||||
|
}
|
||||||
b.write(params[seg.name]);
|
b.write(params[seg.name]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,13 +15,13 @@ part 'routing_result.dart';
|
||||||
|
|
||||||
part 'symlink_route.dart';
|
part 'symlink_route.dart';
|
||||||
|
|
||||||
//final RegExp _param = new RegExp(r':([A-Za-z0-9_]+)(\((.+)\))?');
|
//final RegExp _param = RegExp(r':([A-Za-z0-9_]+)(\((.+)\))?');
|
||||||
//final RegExp _rgxEnd = new RegExp(r'\$+$');
|
//final RegExp _rgxEnd = RegExp(r'\$+$');
|
||||||
//final RegExp _rgxStart = new RegExp(r'^\^+');
|
//final RegExp _rgxStart = RegExp(r'^\^+');
|
||||||
//final RegExp _rgxStraySlashes =
|
//final RegExp _rgxStraySlashes =
|
||||||
// new RegExp(r'(^((\\+/)|(/))+)|(((\\+/)|(/))+$)');
|
// RegExp(r'(^((\\+/)|(/))+)|(((\\+/)|(/))+$)');
|
||||||
//final RegExp _slashDollar = new RegExp(r'/+\$');
|
//final RegExp _slashDollar = RegExp(r'/+\$');
|
||||||
final RegExp _straySlashes = new RegExp(r'(^/+)|(/+$)');
|
final RegExp _straySlashes = 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. :)
|
||||||
class Router<T> {
|
class Router<T> {
|
||||||
|
@ -33,10 +33,10 @@ class Router<T> {
|
||||||
final List<Route<T>> _routes = [];
|
final List<Route<T>> _routes = [];
|
||||||
bool _useCache = false;
|
bool _useCache = false;
|
||||||
|
|
||||||
List<T> get middleware => new List<T>.unmodifiable(_middleware);
|
List<T> get middleware => List<T>.unmodifiable(_middleware);
|
||||||
|
|
||||||
Map<Pattern, Router<T>> get mounted =>
|
Map<Pattern, Router<T>> get mounted =>
|
||||||
new Map<Pattern, Router<T>>.unmodifiable(_mounted);
|
Map<Pattern, Router<T>>.unmodifiable(_mounted);
|
||||||
|
|
||||||
List<Route<T>> get routes {
|
List<Route<T>> get routes {
|
||||||
return _routes.fold<List<Route<T>>>([], (out, route) {
|
return _routes.fold<List<Route<T>>>([], (out, route) {
|
||||||
|
@ -45,7 +45,7 @@ class Router<T> {
|
||||||
route.router.routes.fold<List<Route<T>>>([], (out, r) {
|
route.router.routes.fold<List<Route<T>>>([], (out, r) {
|
||||||
return out
|
return out
|
||||||
..add(
|
..add(
|
||||||
route.path.isEmpty ? r : new Route.join(route, r),
|
route.path.isEmpty ? r : Route.join(route, r),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -71,15 +71,16 @@ class Router<T> {
|
||||||
Route<T> addRoute(String method, String path, T handler,
|
Route<T> addRoute(String method, String path, T handler,
|
||||||
{Iterable<T> middleware}) {
|
{Iterable<T> middleware}) {
|
||||||
middleware ??= <T>[];
|
middleware ??= <T>[];
|
||||||
if (_useCache == true)
|
if (_useCache == true) {
|
||||||
throw new StateError('Cannot add routes after caching is enabled.');
|
throw StateError('Cannot add routes after caching is enabled.');
|
||||||
|
}
|
||||||
|
|
||||||
// Check if any mounted routers can match this
|
// Check if any mounted routers can match this
|
||||||
final handlers = <T>[handler];
|
final handlers = <T>[handler];
|
||||||
|
|
||||||
if (middleware != null) handlers.insertAll(0, middleware);
|
if (middleware != null) handlers.insertAll(0, middleware);
|
||||||
|
|
||||||
final route = new Route<T>(path, method: method, handlers: handlers);
|
final route = Route<T>(path, method: method, handlers: handlers);
|
||||||
_routes.add(route);
|
_routes.add(route);
|
||||||
return route;
|
return route;
|
||||||
}
|
}
|
||||||
|
@ -89,16 +90,16 @@ class Router<T> {
|
||||||
///
|
///
|
||||||
/// The resulting router can be chained, too.
|
/// The resulting router can be chained, too.
|
||||||
_ChainedRouter<T> chain(Iterable<T> middleware) {
|
_ChainedRouter<T> chain(Iterable<T> middleware) {
|
||||||
var piped = new _ChainedRouter<T>(this, middleware);
|
var piped = _ChainedRouter<T>(this, middleware);
|
||||||
var route = new SymlinkRoute<T>('/', piped);
|
var route = SymlinkRoute<T>('/', piped);
|
||||||
_routes.add(route);
|
_routes.add(route);
|
||||||
return piped;
|
return piped;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a [Router] with a duplicated version of this tree.
|
/// Returns a [Router] with a duplicated version of this tree.
|
||||||
Router<T> clone() {
|
Router<T> clone() {
|
||||||
final router = new Router<T>();
|
final router = Router<T>();
|
||||||
final newMounted = new Map<Pattern, Router<T>>.from(mounted);
|
final newMounted = Map<Pattern, Router<T>>.from(mounted);
|
||||||
|
|
||||||
for (var route in routes) {
|
for (var route in routes) {
|
||||||
if (route is! SymlinkRoute<T>) {
|
if (route is! SymlinkRoute<T>) {
|
||||||
|
@ -106,7 +107,7 @@ class Router<T> {
|
||||||
} else if (route is SymlinkRoute<T>) {
|
} else if (route is SymlinkRoute<T>) {
|
||||||
final newRouter = route.router.clone();
|
final newRouter = route.router.clone();
|
||||||
newMounted[route.path] = newRouter;
|
newMounted[route.path] = newRouter;
|
||||||
final symlink = new SymlinkRoute<T>(route.path, newRouter);
|
final symlink = SymlinkRoute<T>(route.path, newRouter);
|
||||||
router._routes.add(symlink);
|
router._routes.add(symlink);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,7 +121,7 @@ class Router<T> {
|
||||||
{callback(String tree),
|
{callback(String tree),
|
||||||
String header = 'Dumping route tree:',
|
String header = 'Dumping route tree:',
|
||||||
String tab = ' '}) {
|
String tab = ' '}) {
|
||||||
final buf = new StringBuffer();
|
final buf = StringBuffer();
|
||||||
int tabs = 0;
|
int tabs = 0;
|
||||||
|
|
||||||
if (header != null && header.isNotEmpty) {
|
if (header != null && header.isNotEmpty) {
|
||||||
|
@ -130,7 +131,9 @@ class Router<T> {
|
||||||
buf.writeln('<root>');
|
buf.writeln('<root>');
|
||||||
|
|
||||||
indent() {
|
indent() {
|
||||||
for (int i = 0; i < tabs; i++) buf.write(tab);
|
for (int i = 0; i < tabs; i++) {
|
||||||
|
buf.write(tab);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dumpRouter(Router router) {
|
dumpRouter(Router router) {
|
||||||
|
@ -167,7 +170,7 @@ class Router<T> {
|
||||||
SymlinkRoute<T> group(String path, void callback(Router<T> router),
|
SymlinkRoute<T> group(String path, void callback(Router<T> router),
|
||||||
{Iterable<T> middleware, String name}) {
|
{Iterable<T> middleware, String name}) {
|
||||||
middleware ??= <T>[];
|
middleware ??= <T>[];
|
||||||
final router = new Router<T>().._middleware.addAll(middleware);
|
final router = Router<T>().._middleware.addAll(middleware);
|
||||||
callback(router);
|
callback(router);
|
||||||
return mount(path, router)..name = name;
|
return mount(path, router)..name = name;
|
||||||
}
|
}
|
||||||
|
@ -225,7 +228,7 @@ class Router<T> {
|
||||||
|
|
||||||
// Search by path
|
// Search by path
|
||||||
if (!resolved) {
|
if (!resolved) {
|
||||||
var scanner = new SpanScanner(param.replaceAll(_straySlashes, ''));
|
var scanner = SpanScanner(param.replaceAll(_straySlashes, ''));
|
||||||
for (Route route in search.routes) {
|
for (Route route in search.routes) {
|
||||||
int pos = scanner.position;
|
int pos = scanner.position;
|
||||||
if (route.parser.parse(scanner).successful && scanner.isDone) {
|
if (route.parser.parse(scanner).successful && scanner.isDone) {
|
||||||
|
@ -238,28 +241,30 @@ class Router<T> {
|
||||||
|
|
||||||
resolved = true;
|
resolved = true;
|
||||||
break;
|
break;
|
||||||
} else
|
} else {
|
||||||
scanner.position = pos;
|
scanner.position = pos;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!resolved) {
|
if (!resolved) {
|
||||||
throw new RoutingException(
|
throw RoutingException(
|
||||||
'Cannot resolve route for link param "$param".');
|
'Cannot resolve route for link param "$param".');
|
||||||
}
|
}
|
||||||
} else if (param is Route) {
|
} else if (param is Route) {
|
||||||
segments.add(param.path.replaceAll(_straySlashes, ''));
|
segments.add(param.path.replaceAll(_straySlashes, ''));
|
||||||
} else if (param is Map<String, dynamic>) {
|
} else if (param is Map<String, dynamic>) {
|
||||||
if (lastRoute == null) {
|
if (lastRoute == null) {
|
||||||
throw new RoutingException(
|
throw RoutingException(
|
||||||
'Maps in link params must be preceded by a Route or String.');
|
'Maps in link params must be preceded by a Route or String.');
|
||||||
} else {
|
} else {
|
||||||
segments.removeLast();
|
segments.removeLast();
|
||||||
segments.add(lastRoute.makeUri(param).replaceAll(_straySlashes, ''));
|
segments.add(lastRoute.makeUri(param).replaceAll(_straySlashes, ''));
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
throw new RoutingException(
|
throw RoutingException(
|
||||||
'Link param $param is not Route, String, or Map<String, dynamic>.');
|
'Link param $param is not Route, String, or Map<String, dynamic>.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return absolute
|
return absolute
|
||||||
|
@ -273,7 +278,7 @@ class Router<T> {
|
||||||
{String method = 'GET', bool strip = true}) {
|
{String method = 'GET', bool strip = true}) {
|
||||||
final cleanRelative =
|
final cleanRelative =
|
||||||
strip == false ? relative : stripStraySlashes(relative);
|
strip == false ? relative : stripStraySlashes(relative);
|
||||||
var scanner = new SpanScanner(cleanRelative);
|
var scanner = SpanScanner(cleanRelative);
|
||||||
|
|
||||||
bool crawl(Router<T> r) {
|
bool crawl(Router<T> r) {
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
@ -292,7 +297,7 @@ class Router<T> {
|
||||||
var parseResult = route.parser.parse(scanner);
|
var parseResult = route.parser.parse(scanner);
|
||||||
|
|
||||||
if (parseResult.successful && scanner.isDone) {
|
if (parseResult.successful && scanner.isDone) {
|
||||||
var result = new RoutingResult<T>(
|
var result = RoutingResult<T>(
|
||||||
parseResult: parseResult,
|
parseResult: parseResult,
|
||||||
params: parseResult.value.params,
|
params: parseResult.value.params,
|
||||||
shallowRoute: route,
|
shallowRoute: route,
|
||||||
|
@ -342,10 +347,10 @@ class Router<T> {
|
||||||
|
|
||||||
/// Incorporates another [Router]'s routes into this one's.
|
/// Incorporates another [Router]'s routes into this one's.
|
||||||
SymlinkRoute<T> mount(String path, Router<T> router) {
|
SymlinkRoute<T> mount(String path, Router<T> router) {
|
||||||
final route = new SymlinkRoute<T>(path, router);
|
final route = SymlinkRoute<T>(path, router);
|
||||||
_mounted[route.path] = router;
|
_mounted[route.path] = router;
|
||||||
_routes.add(route);
|
_routes.add(route);
|
||||||
//route._head = new RegExp(route.matcher.pattern.replaceAll(_rgxEnd, ''));
|
//route._head = RegExp(route.matcher.pattern.replaceAll(_rgxEnd, ''));
|
||||||
|
|
||||||
return route;
|
return route;
|
||||||
}
|
}
|
||||||
|
@ -414,7 +419,7 @@ class _ChainedRouter<T> extends Router<T> {
|
||||||
@override
|
@override
|
||||||
SymlinkRoute<T> group(String path, void callback(Router<T> router),
|
SymlinkRoute<T> group(String path, void callback(Router<T> router),
|
||||||
{Iterable<T> middleware, String name}) {
|
{Iterable<T> middleware, String name}) {
|
||||||
final router = new _ChainedRouter<T>(
|
final router = _ChainedRouter<T>(
|
||||||
_root, []..addAll(_handlers)..addAll(middleware ?? []));
|
_root, []..addAll(_handlers)..addAll(middleware ?? []));
|
||||||
callback(router);
|
callback(router);
|
||||||
return mount(path, router)..name = name;
|
return mount(path, router)..name = name;
|
||||||
|
@ -430,9 +435,9 @@ class _ChainedRouter<T> extends Router<T> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_ChainedRouter<T> chain(Iterable<T> middleware) {
|
_ChainedRouter<T> chain(Iterable<T> middleware) {
|
||||||
final piped = new _ChainedRouter<T>.empty().._root = _root;
|
final piped = _ChainedRouter<T>.empty().._root = _root;
|
||||||
piped._handlers.addAll([]..addAll(_handlers)..addAll(middleware));
|
piped._handlers.addAll([]..addAll(_handlers)..addAll(middleware));
|
||||||
var route = new SymlinkRoute<T>('/', piped);
|
var route = SymlinkRoute<T>('/', piped);
|
||||||
_routes.add(route);
|
_routes.add(route);
|
||||||
return piped;
|
return piped;
|
||||||
}
|
}
|
||||||
|
@ -440,7 +445,7 @@ class _ChainedRouter<T> extends Router<T> {
|
||||||
|
|
||||||
/// Optimizes a router by condensing all its routes into one level.
|
/// Optimizes a router by condensing all its routes into one level.
|
||||||
Router<T> flatten<T>(Router<T> router) {
|
Router<T> flatten<T>(Router<T> router) {
|
||||||
var flattened = new Router<T>();
|
var flattened = Router<T>();
|
||||||
|
|
||||||
for (var route in router.routes) {
|
for (var route in router.routes) {
|
||||||
if (route is SymlinkRoute<T>) {
|
if (route is SymlinkRoute<T>) {
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
/// Represents an error in route configuration or navigation.
|
/// Represents an error in route configuration or navigation.
|
||||||
abstract class RoutingException extends Exception {
|
abstract class RoutingException extends Exception {
|
||||||
factory RoutingException(String message) =>
|
factory RoutingException(String message) =>
|
||||||
new _RoutingExceptionImpl(message);
|
_RoutingExceptionImpl(message);
|
||||||
|
|
||||||
/// Occurs when trying to resolve the parent of a [Route] without a parent.
|
/// Occurs when trying to resolve the parent of a [Route] without a parent.
|
||||||
factory RoutingException.orphan() => new _RoutingExceptionImpl(
|
factory RoutingException.orphan() => _RoutingExceptionImpl(
|
||||||
"Tried to resolve path '..' on a route that has no parent.");
|
"Tried to resolve path '..' on a route that has no parent.");
|
||||||
|
|
||||||
/// Occurs when the user attempts to navigate to a non-existent route.
|
/// Occurs when the user attempts to navigate to a non-existent route.
|
||||||
factory RoutingException.noSuchRoute(String path) =>
|
factory RoutingException.noSuchRoute(String path) =>
|
||||||
new _RoutingExceptionImpl(
|
_RoutingExceptionImpl(
|
||||||
"Tried to navigate to non-existent route: '$path'.");
|
"Tried to navigate to non-existent route: '$path'.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,9 @@ class RoutingResult<T> {
|
||||||
RoutingResult<T> get deepest {
|
RoutingResult<T> get deepest {
|
||||||
var search = this;
|
var search = this;
|
||||||
|
|
||||||
while (search?.nested?.isNotEmpty == true) search = search.nested.first;
|
while (search?.nested?.isNotEmpty == true) {
|
||||||
|
search = search.nested.first;
|
||||||
|
}
|
||||||
|
|
||||||
return search;
|
return search;
|
||||||
}
|
}
|
||||||
|
@ -54,7 +56,9 @@ class RoutingResult<T> {
|
||||||
handlers.addAll(result.handlers);
|
handlers.addAll(result.handlers);
|
||||||
|
|
||||||
if (result.nested?.isNotEmpty == true) {
|
if (result.nested?.isNotEmpty == true) {
|
||||||
for (var r in result.nested) crawl(r);
|
for (var r in result.nested) {
|
||||||
|
crawl(r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +75,9 @@ class RoutingResult<T> {
|
||||||
params.addAll(result.params);
|
params.addAll(result.params);
|
||||||
|
|
||||||
if (result.nested?.isNotEmpty == true) {
|
if (result.nested?.isNotEmpty == true) {
|
||||||
for (var r in result.nested) crawl(r);
|
for (var r in result.nested) {
|
||||||
|
crawl(r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,9 @@ String stripStray(String haystack, String needle) {
|
||||||
firstSlash = -1;
|
firstSlash = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (firstSlash == haystack.length - 1)
|
if (firstSlash == haystack.length - 1) {
|
||||||
return haystack.length == 1 ? '' : haystack.substring(0, firstSlash);
|
return haystack.length == 1 ? '' : haystack.substring(0, firstSlash);
|
||||||
|
}
|
||||||
|
|
||||||
// Find last leading index of slash
|
// Find last leading index of slash
|
||||||
for (int i = firstSlash + 1; i < haystack.length; i++) {
|
for (int i = firstSlash + 1; i < haystack.length; i++) {
|
||||||
|
|
|
@ -2,7 +2,7 @@ import 'package:angel_route/angel_route.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
var router = new Router<String>()
|
var router = Router<String>()
|
||||||
..chain(['a']).group('/b', (router) {
|
..chain(['a']).group('/b', (router) {
|
||||||
router.chain(['c']).chain(['d']).group('/e', (router) {
|
router.chain(['c']).chain(['d']).group('/e', (router) {
|
||||||
router.get('f', 'g');
|
router.get('f', 'g');
|
||||||
|
|
|
@ -2,7 +2,7 @@ import 'package:angel_route/angel_route.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
final router = new Router();
|
final router = Router();
|
||||||
|
|
||||||
router.get('/', 'GET').name = 'root';
|
router.get('/', 'GET').name = 'root';
|
||||||
router.get('/user/:id', 'GET');
|
router.get('/user/:id', 'GET');
|
||||||
|
|
|
@ -2,14 +2,14 @@ import 'package:angel_route/angel_route.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
final router = new Router()..get('/hello', '')..get('/user/:id', '');
|
final router = Router()..get('/hello', '')..get('/user/:id', '');
|
||||||
|
|
||||||
router.group('/book/:id', (router) {
|
router.group('/book/:id', (router) {
|
||||||
router.get('/reviews', '');
|
router.get('/reviews', '');
|
||||||
router.get('/readers/:readerId', '');
|
router.get('/readers/:readerId', '');
|
||||||
});
|
});
|
||||||
|
|
||||||
router.mount('/color', new Router()..get('/:name/shades', ''));
|
router.mount('/color', Router()..get('/:name/shades', ''));
|
||||||
|
|
||||||
setUp(router.dumpTree);
|
setUp(router.dumpTree);
|
||||||
|
|
||||||
|
@ -17,7 +17,9 @@ main() {
|
||||||
final p = {};
|
final p = {};
|
||||||
final resolved = router.resolveAll(path, path);
|
final resolved = router.resolveAll(path, path);
|
||||||
print('Resolved $path => ${resolved.map((r) => r.allParams).toList()}');
|
print('Resolved $path => ${resolved.map((r) => r.allParams).toList()}');
|
||||||
for (final result in resolved) p.addAll(result.allParams);
|
for (final result in resolved) {
|
||||||
|
p.addAll(result.allParams);
|
||||||
|
}
|
||||||
expect(p, equals(params));
|
expect(p, equals(params));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import 'package:angel_route/angel_route.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
var router = new Router()
|
var router = Router()
|
||||||
..get('/int/int:id', '')
|
..get('/int/int:id', '')
|
||||||
..get('/double/double:id', '')
|
..get('/double/double:id', '')
|
||||||
..get('/num/num:id', '');
|
..get('/num/num:id', '');
|
||||||
|
|
|
@ -3,7 +3,7 @@ import 'package:test/test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test('resolve / on /', () {
|
test('resolve / on /', () {
|
||||||
var router = new Router()
|
var router = Router()
|
||||||
..group('/', (router) {
|
..group('/', (router) {
|
||||||
router.group('/', (router) {
|
router.group('/', (router) {
|
||||||
router.get('/', 'ok');
|
router.get('/', 'ok');
|
||||||
|
|
|
@ -4,14 +4,14 @@ import 'package:angel_route/angel_route.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
const List<Map<String, String>> people = const [
|
const List<Map<String, String>> people = [
|
||||||
const {'name': 'John Smith'}
|
{'name': 'John Smith'}
|
||||||
];
|
];
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
http.Client client;
|
http.Client client;
|
||||||
|
|
||||||
final Router router = new Router();
|
final Router router = Router();
|
||||||
HttpServer server;
|
HttpServer server;
|
||||||
String url;
|
String url;
|
||||||
|
|
||||||
|
@ -48,14 +48,14 @@ main() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
final beatles = new Router();
|
final beatles = Router();
|
||||||
|
|
||||||
beatles.post('/spinal_clacker', (req, res) {
|
beatles.post('/spinal_clacker', (req, res) {
|
||||||
res.write('come ');
|
res.write('come ');
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
final yellow = new Router()
|
final yellow = Router()
|
||||||
..get('/submarine', (req, res) {
|
..get('/submarine', (req, res) {
|
||||||
res.write('we all live in a');
|
res.write('we all live in a');
|
||||||
return false;
|
return false;
|
||||||
|
@ -73,7 +73,7 @@ main() {
|
||||||
router.mount('/beatles', beatles);
|
router.mount('/beatles', beatles);
|
||||||
|
|
||||||
setUp(() async {
|
setUp(() async {
|
||||||
client = new http.Client();
|
client = http.Client();
|
||||||
|
|
||||||
router.dumpTree();
|
router.dumpTree();
|
||||||
server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
|
server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
|
||||||
|
@ -85,7 +85,7 @@ main() {
|
||||||
// Easy middleware pipeline
|
// Easy middleware pipeline
|
||||||
final results =
|
final results =
|
||||||
router.resolveAbsolute(req.uri.toString(), method: req.method);
|
router.resolveAbsolute(req.uri.toString(), method: req.method);
|
||||||
final pipeline = new MiddlewarePipeline(results);
|
final pipeline = MiddlewarePipeline(results);
|
||||||
|
|
||||||
if (pipeline.handlers.isEmpty) {
|
if (pipeline.handlers.isEmpty) {
|
||||||
res
|
res
|
||||||
|
|
|
@ -3,7 +3,7 @@ import 'package:test/test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test('uri params decoded', () {
|
test('uri params decoded', () {
|
||||||
var router = new Router()..get('/a/:a/b/:b', '');
|
var router = Router()..get('/a/:a/b/:b', '');
|
||||||
|
|
||||||
var encoded =
|
var encoded =
|
||||||
'/a/' + Uri.encodeComponent('<<<') + '/b/' + Uri.encodeComponent('???');
|
'/a/' + Uri.encodeComponent('<<<') + '/b/' + Uri.encodeComponent('???');
|
||||||
|
|
|
@ -2,7 +2,7 @@ import 'package:angel_route/angel_route.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
var router = new Router();
|
var router = Router();
|
||||||
router.get('/songs/*/key', 'of life');
|
router.get('/songs/*/key', 'of life');
|
||||||
router.get('/isnt/she/*', 'lovely');
|
router.get('/isnt/she/*', 'lovely');
|
||||||
router.all('*', 'stevie');
|
router.all('*', 'stevie');
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import 'package:angel_route/browser.dart';
|
import 'package:angel_route/browser.dart';
|
||||||
import '../shared/basic.dart';
|
import '../shared/basic.dart';
|
||||||
|
|
||||||
main() => basic(new BrowserRouter(hash: true));
|
main() => basic(BrowserRouter(hash: true));
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import 'package:angel_route/browser.dart';
|
import 'package:angel_route/browser.dart';
|
||||||
import '../shared/basic.dart';
|
import '../shared/basic.dart';
|
||||||
|
|
||||||
main() => basic(new BrowserRouter());
|
main() => basic(BrowserRouter());
|
||||||
|
|
|
@ -12,13 +12,13 @@ basic(BrowserRouter router) {
|
||||||
$h1.text = 'No Active Route';
|
$h1.text = 'No Active Route';
|
||||||
$ul.children
|
$ul.children
|
||||||
..clear()
|
..clear()
|
||||||
..add(new LIElement()..text = '(empty)');
|
..add(LIElement()..text = '(empty)');
|
||||||
} else {
|
} else {
|
||||||
$h1.text = 'Active Route: ${route.name ?? route.path}';
|
$h1.text = 'Active Route: ${route.name ?? route.path}';
|
||||||
$ul.children
|
$ul.children
|
||||||
..clear()
|
..clear()
|
||||||
..addAll(result.allHandlers
|
..addAll(result.allHandlers
|
||||||
.map((handler) => new LIElement()..text = handler.toString()));
|
.map((handler) => LIElement()..text = handler.toString()));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue