platform/lib/src/route.dart

100 lines
2.8 KiB
Dart
Raw Normal View History

2016-10-11 18:53:32 +00:00
final RegExp _rgxEnd = new RegExp(r'\$');
final RegExp _rgxStart = new RegExp(r'\^');
final RegExp _straySlashes = new RegExp(r'(^/+)|(/+$)');
class Route {
final List<Route> _children = [];
final List _handlers = [];
RegExp _matcher;
Route _parent;
String _path;
List<Route> get children => new List.unmodifiable(_children);
List get handlers => new List.unmodifiable(_handlers);
RegExp get matcher => _matcher;
final String method;
final String name;
Route get parent => _parent;
String get path => _path;
Route(Pattern path,
{Iterable<Route> children: const [],
Iterable handlers: const [],
this.method: "GET",
this.name: null}) {
if (children != null) _children.addAll(children);
if (handlers != null) _handlers.addAll(handlers);
if (path is RegExp) {
_matcher = path;
_path = path.pattern;
} else {
_matcher = new RegExp(_path = path
.toString()
.replaceAll(_straySlashes, '')
.replaceAll(new RegExp(r'\/\*$'), "*")
.replaceAll(new RegExp('\/'), r'\/')
.replaceAll(new RegExp(':[a-zA-Z_]+'), '([^\/]+)')
.replaceAll(new RegExp('\\*'), '.*'));
}
}
factory Route.join(Route parent, Route child) {
final String path1 = parent.path.replaceAll(_straySlashes, '');
final String path2 = child.path.replaceAll(_straySlashes, '');
final String pattern1 = parent.matcher.pattern.replaceAll(_rgxEnd, '');
final String pattern2 = child.matcher.pattern.replaceAll(_rgxStart, '');
final route = new Route(new RegExp('$pattern1/$pattern2'),
children: child.children,
handlers: child.handlers,
method: child.method,
name: child.name);
return route
..parent = parent
.._path = '$path1/$path2';
}
Route addChild(Route route, {bool join: true}) {
Route created = join ? new Route.join(this, route) : route;
_children.add(created);
return created;
}
Route child(Pattern path,
{Iterable<Route> children: const [],
Iterable handlers: const [],
String method: "GET",
String name: null}) {
final route = new Route(path,
children: children, handlers: handlers, method: method, name: name);
return addChild(route);
}
Match match(String path) => matcher.firstMatch(path);
Route resolve(String path) {
if (path.isEmpty ||
path == '.' ||
path.replaceAll(_straySlashes, '').isEmpty) {
return this;
} else {
final segments = path.split('/');
for (Route route in children) {
final subPath = '${this.path}/${segments[0]}';
if (route.match(subPath) != null) {
if (segments.length == 1)
return route;
else {
return route.resolve(segments.skip(1).join('/'));
}
}
}
return null;
}
}
}