3.0.4
This commit is contained in:
parent
0e3e7ee9bb
commit
0f529c5625
7 changed files with 94 additions and 50 deletions
|
@ -1,3 +1,8 @@
|
|||
# 3.0.4
|
||||
* Add `RouteResult` class, which allows segments (i.e. wildcard) to
|
||||
modify the `tail`.
|
||||
* Add more wildcard tests.
|
||||
|
||||
# 3.0.3
|
||||
* Support trailing text after parameters with custom Regexes.
|
||||
|
||||
|
|
|
@ -95,8 +95,8 @@ class RouteDefinition {
|
|||
|
||||
RouteDefinition(this.segments);
|
||||
|
||||
Parser<Map<String, dynamic>> compile() {
|
||||
Parser<Map<String, dynamic>> out;
|
||||
Parser<RouteResult> compile() {
|
||||
Parser<RouteResult> out;
|
||||
|
||||
for (int i = 0; i < segments.length; i++) {
|
||||
var s = segments[i];
|
||||
|
@ -105,7 +105,7 @@ class RouteDefinition {
|
|||
out = s.compile(isLast);
|
||||
else
|
||||
out = s.compileNext(
|
||||
out.then(match('/')).index(0).cast<Map<String, dynamic>>(), isLast);
|
||||
out.then(match('/')).index(0).cast<RouteResult>(), isLast);
|
||||
}
|
||||
|
||||
return out;
|
||||
|
@ -113,10 +113,9 @@ class RouteDefinition {
|
|||
}
|
||||
|
||||
abstract class RouteSegment {
|
||||
Parser<Map<String, dynamic>> compile(bool isLast);
|
||||
Parser<RouteResult> compile(bool isLast);
|
||||
|
||||
Parser<Map<String, dynamic>> compileNext(
|
||||
Parser<Map<String, dynamic>> p, bool isLast);
|
||||
Parser<RouteResult> compileNext(Parser<RouteResult> p, bool isLast);
|
||||
}
|
||||
|
||||
class SlashSegment implements RouteSegment {
|
||||
|
@ -125,14 +124,13 @@ class SlashSegment implements RouteSegment {
|
|||
const SlashSegment();
|
||||
|
||||
@override
|
||||
Parser<Map<String, dynamic>> compile(bool isLast) {
|
||||
return match(rgx).map((_) => {});
|
||||
Parser<RouteResult> compile(bool isLast) {
|
||||
return match(rgx).map((_) => RouteResult({}));
|
||||
}
|
||||
|
||||
@override
|
||||
Parser<Map<String, dynamic>> compileNext(
|
||||
Parser<Map<String, dynamic>> p, bool isLast) {
|
||||
return p.then(compile(isLast)).index(0).cast<Map<String, dynamic>>();
|
||||
Parser<RouteResult> compileNext(Parser<RouteResult> p, bool isLast) {
|
||||
return p.then(compile(isLast)).index(0).cast<RouteResult>();
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -150,14 +148,13 @@ class ConstantSegment extends RouteSegment {
|
|||
}
|
||||
|
||||
@override
|
||||
Parser<Map<String, dynamic>> compile(bool isLast) {
|
||||
return match<Map<String, dynamic>>(text).value((r) => <String, dynamic>{});
|
||||
Parser<RouteResult> compile(bool isLast) {
|
||||
return match(text).map((r) => RouteResult({}));
|
||||
}
|
||||
|
||||
@override
|
||||
Parser<Map<String, dynamic>> compileNext(
|
||||
Parser<Map<String, dynamic>> p, bool isLast) {
|
||||
return p.then(compile(isLast)).index(0).cast<Map<String, dynamic>>();
|
||||
Parser<RouteResult> compileNext(Parser<RouteResult> p, bool isLast) {
|
||||
return p.then(compile(isLast)).index(0).cast<RouteResult>();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,22 +173,27 @@ class WildcardSegment extends RouteSegment {
|
|||
return r'[^/]*';
|
||||
}
|
||||
|
||||
Parser<Map<String, dynamic>> _compile(bool isLast) {
|
||||
var rgx = RegExp('$pre${_symbol(isLast)}$post');
|
||||
return match(rgx);
|
||||
RegExp _compile(bool isLast) {
|
||||
return RegExp('$pre(${_symbol(isLast)})$post');
|
||||
// if (isLast) return match(new RegExp(r'.*'));
|
||||
// return match(new RegExp(r'[^/]*'));
|
||||
}
|
||||
|
||||
@override
|
||||
Parser<Map<String, dynamic>> compile(bool isLast) {
|
||||
return _compile(isLast).map((r) => {});
|
||||
Parser<RouteResult> compile(bool isLast) {
|
||||
return match(_compile(isLast))
|
||||
.map((r) => RouteResult({}, tail: r.scanner.lastMatch[1]));
|
||||
}
|
||||
|
||||
@override
|
||||
Parser<Map<String, dynamic>> compileNext(
|
||||
Parser<Map<String, dynamic>> p, bool isLast) {
|
||||
return p.then(_compile(isLast)).index(0).cast<Map<String, dynamic>>();
|
||||
Parser<RouteResult> compileNext(Parser<RouteResult> p, bool isLast) {
|
||||
return p.then(compile(isLast)).map((r) {
|
||||
var items = r.value.cast<RouteResult>();
|
||||
var a = items[0], b = items[1];
|
||||
return a
|
||||
..addAll(b?.params ?? {})
|
||||
.._setTail(b?.tail);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -206,16 +208,15 @@ class OptionalSegment extends ParameterSegment {
|
|||
}
|
||||
|
||||
@override
|
||||
Parser<Map<String, dynamic>> compile(bool isLast) {
|
||||
Parser<RouteResult> compile(bool isLast) {
|
||||
return super.compile(isLast).opt();
|
||||
}
|
||||
|
||||
@override
|
||||
Parser<Map<String, dynamic>> compileNext(
|
||||
Parser<Map<String, dynamic>> p, bool isLast) {
|
||||
Parser<RouteResult> compileNext(Parser<RouteResult> p, bool isLast) {
|
||||
return p.then(_compile().opt()).map((r) {
|
||||
if (r.value[1] == null) return r.value[0] as Map<String, dynamic>;
|
||||
return (r.value[0] as Map<String, dynamic>)
|
||||
if (r.value[1] == null) return r.value[0] as RouteResult;
|
||||
return (r.value[0] as RouteResult)
|
||||
..addAll({name: Uri.decodeComponent(r.value[1] as String)});
|
||||
});
|
||||
}
|
||||
|
@ -240,16 +241,15 @@ class ParameterSegment extends RouteSegment {
|
|||
}
|
||||
|
||||
@override
|
||||
Parser<Map<String, dynamic>> compile(bool isLast) {
|
||||
Parser<RouteResult> compile(bool isLast) {
|
||||
return _compile()
|
||||
.map<Map<String, dynamic>>((r) => {name: Uri.decodeComponent(r.value)});
|
||||
.map((r) => RouteResult({name: Uri.decodeComponent(r.value)}));
|
||||
}
|
||||
|
||||
@override
|
||||
Parser<Map<String, dynamic>> compileNext(
|
||||
Parser<Map<String, dynamic>> p, bool isLast) {
|
||||
Parser<RouteResult> compileNext(Parser<RouteResult> p, bool isLast) {
|
||||
return p.then(_compile()).map((r) {
|
||||
return (r.value[0] as Map<String, dynamic>)
|
||||
return (r.value[0] as RouteResult)
|
||||
..addAll({name: Uri.decodeComponent(r.value[1] as String)});
|
||||
});
|
||||
}
|
||||
|
@ -273,16 +273,15 @@ class ParsedParameterSegment extends RouteSegment {
|
|||
}
|
||||
|
||||
@override
|
||||
Parser<Map<String, dynamic>> compile(bool isLast) {
|
||||
return parameter._compile().map(
|
||||
(r) => {parameter.name: getValue(Uri.decodeComponent(r.span.text))});
|
||||
Parser<RouteResult> compile(bool isLast) {
|
||||
return parameter._compile().map((r) => RouteResult(
|
||||
{parameter.name: getValue(Uri.decodeComponent(r.span.text))}));
|
||||
}
|
||||
|
||||
@override
|
||||
Parser<Map<String, dynamic>> compileNext(
|
||||
Parser<Map<String, dynamic>> p, bool isLast) {
|
||||
Parser<RouteResult> compileNext(Parser<RouteResult> p, bool isLast) {
|
||||
return p.then(parameter._compile()).map((r) {
|
||||
return (r.value[0] as Map<String, dynamic>)
|
||||
return (r.value[0] as RouteResult)
|
||||
..addAll({
|
||||
parameter.name: getValue(Uri.decodeComponent(r.value[1] as String))
|
||||
});
|
||||
|
|
|
@ -8,15 +8,14 @@ class Route<T> {
|
|||
final Map<String, Map<String, dynamic>> _cache = {};
|
||||
final RouteDefinition _routeDefinition;
|
||||
String name;
|
||||
Parser<Map<String, dynamic>> _parser;
|
||||
Parser<RouteResult> _parser;
|
||||
|
||||
Route(this.path, {@required this.method, @required this.handlers})
|
||||
: _routeDefinition = RouteGrammar.routeDefinition
|
||||
.parse(new SpanScanner(path.replaceAll(_straySlashes, '')))
|
||||
.value {
|
||||
if (_routeDefinition?.segments?.isNotEmpty != true)
|
||||
_parser =
|
||||
match<Map<String, dynamic>>('').value((r) => <String, dynamic>{});
|
||||
_parser = match('').map((r) => RouteResult({}));
|
||||
}
|
||||
|
||||
factory Route.join(Route<T> a, Route<T> b) {
|
||||
|
@ -26,8 +25,7 @@ class Route<T> {
|
|||
method: b.method, handlers: b.handlers);
|
||||
}
|
||||
|
||||
Parser<Map<String, dynamic>> get parser =>
|
||||
_parser ??= _routeDefinition.compile();
|
||||
Parser<RouteResult> get parser => _parser ??= _routeDefinition.compile();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
|
@ -57,3 +55,23 @@ class Route<T> {
|
|||
return b.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/// The result of matching an individual route.
|
||||
class RouteResult {
|
||||
/// The parsed route parameters.
|
||||
final Map<String, dynamic> params;
|
||||
|
||||
/// Optional. An explicit "tail" value to set.
|
||||
String get tail => _tail;
|
||||
|
||||
String _tail;
|
||||
|
||||
RouteResult(this.params, {String tail}) : _tail = tail;
|
||||
|
||||
void _setTail(String v) => _tail ??= v;
|
||||
|
||||
/// Adds parameters.
|
||||
void addAll(Map<String, dynamic> map) {
|
||||
params.addAll(map);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -292,9 +292,10 @@ class Router<T> {
|
|||
if (parseResult.successful && scanner.isDone) {
|
||||
var result = new RoutingResult<T>(
|
||||
parseResult: parseResult,
|
||||
params: parseResult.value,
|
||||
params: parseResult.value.params,
|
||||
shallowRoute: route,
|
||||
shallowRouter: this);
|
||||
shallowRouter: this,
|
||||
tail: (parseResult.value.tail ?? '') + scanner.rest);
|
||||
out.add(result);
|
||||
success = true;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ part of angel_route.src.router;
|
|||
/// Represents a complex result of navigating to a path.
|
||||
class RoutingResult<T> {
|
||||
/// The parse result that matched the given sub-path.
|
||||
final ParseResult<Map<String, dynamic>> parseResult;
|
||||
final ParseResult<RouteResult> parseResult;
|
||||
|
||||
/// A nested instance, if a sub-path was matched.
|
||||
final Iterable<RoutingResult<T>> nested;
|
||||
|
@ -85,7 +85,7 @@ class RoutingResult<T> {
|
|||
this.nested,
|
||||
this.shallowRoute,
|
||||
this.shallowRouter,
|
||||
this.tail}) {
|
||||
@required this.tail}) {
|
||||
this.params.addAll(params ?? {});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.3
|
||||
version: 3.0.4
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/angel_route
|
||||
environment:
|
||||
|
|
|
@ -22,4 +22,25 @@ void main() {
|
|||
router.resolveAbsolute('/isnt/she/fierce%20harmonica%solo').first;
|
||||
expect(result.handlers, ['lovely']);
|
||||
});
|
||||
|
||||
test('tail explicitly set intermediate', () {
|
||||
var results = router.resolveAbsolute('/songs/in_the/key');
|
||||
var result = results.first;
|
||||
print(results.map((r) => {r.route.path: r.tail}));
|
||||
expect(result.tail, 'in_the');
|
||||
});
|
||||
|
||||
test('tail explicitly set at end', () {
|
||||
var results = router.resolveAbsolute('/isnt/she/epic');
|
||||
var result = results.first;
|
||||
print(results.map((r) => {r.route.path: r.tail}));
|
||||
expect(result.tail, 'epic');
|
||||
});
|
||||
|
||||
test('tail with trailing', () {
|
||||
var results = router.resolveAbsolute('/isnt/she/epic/fail');
|
||||
var result = results.first;
|
||||
print(results.map((r) => {r.route.path: r.tail}));
|
||||
expect(result.tail, 'epic/fail');
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue