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
|
# 3.0.3
|
||||||
* Support trailing text after parameters with custom Regexes.
|
* Support trailing text after parameters with custom Regexes.
|
||||||
|
|
||||||
|
|
|
@ -95,8 +95,8 @@ class RouteDefinition {
|
||||||
|
|
||||||
RouteDefinition(this.segments);
|
RouteDefinition(this.segments);
|
||||||
|
|
||||||
Parser<Map<String, dynamic>> compile() {
|
Parser<RouteResult> compile() {
|
||||||
Parser<Map<String, dynamic>> out;
|
Parser<RouteResult> out;
|
||||||
|
|
||||||
for (int i = 0; i < segments.length; i++) {
|
for (int i = 0; i < segments.length; i++) {
|
||||||
var s = segments[i];
|
var s = segments[i];
|
||||||
|
@ -105,7 +105,7 @@ class RouteDefinition {
|
||||||
out = s.compile(isLast);
|
out = s.compile(isLast);
|
||||||
else
|
else
|
||||||
out = s.compileNext(
|
out = s.compileNext(
|
||||||
out.then(match('/')).index(0).cast<Map<String, dynamic>>(), isLast);
|
out.then(match('/')).index(0).cast<RouteResult>(), isLast);
|
||||||
}
|
}
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
|
@ -113,10 +113,9 @@ class RouteDefinition {
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class RouteSegment {
|
abstract class RouteSegment {
|
||||||
Parser<Map<String, dynamic>> compile(bool isLast);
|
Parser<RouteResult> compile(bool isLast);
|
||||||
|
|
||||||
Parser<Map<String, dynamic>> compileNext(
|
Parser<RouteResult> compileNext(Parser<RouteResult> p, bool isLast);
|
||||||
Parser<Map<String, dynamic>> p, bool isLast);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class SlashSegment implements RouteSegment {
|
class SlashSegment implements RouteSegment {
|
||||||
|
@ -125,14 +124,13 @@ class SlashSegment implements RouteSegment {
|
||||||
const SlashSegment();
|
const SlashSegment();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Parser<Map<String, dynamic>> compile(bool isLast) {
|
Parser<RouteResult> compile(bool isLast) {
|
||||||
return match(rgx).map((_) => {});
|
return match(rgx).map((_) => RouteResult({}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Parser<Map<String, dynamic>> compileNext(
|
Parser<RouteResult> compileNext(Parser<RouteResult> p, bool isLast) {
|
||||||
Parser<Map<String, dynamic>> p, bool isLast) {
|
return p.then(compile(isLast)).index(0).cast<RouteResult>();
|
||||||
return p.then(compile(isLast)).index(0).cast<Map<String, dynamic>>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -150,14 +148,13 @@ class ConstantSegment extends RouteSegment {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Parser<Map<String, dynamic>> compile(bool isLast) {
|
Parser<RouteResult> compile(bool isLast) {
|
||||||
return match<Map<String, dynamic>>(text).value((r) => <String, dynamic>{});
|
return match(text).map((r) => RouteResult({}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Parser<Map<String, dynamic>> compileNext(
|
Parser<RouteResult> compileNext(Parser<RouteResult> p, bool isLast) {
|
||||||
Parser<Map<String, dynamic>> p, bool isLast) {
|
return p.then(compile(isLast)).index(0).cast<RouteResult>();
|
||||||
return p.then(compile(isLast)).index(0).cast<Map<String, dynamic>>();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,22 +173,27 @@ class WildcardSegment extends RouteSegment {
|
||||||
return r'[^/]*';
|
return r'[^/]*';
|
||||||
}
|
}
|
||||||
|
|
||||||
Parser<Map<String, dynamic>> _compile(bool isLast) {
|
RegExp _compile(bool isLast) {
|
||||||
var rgx = RegExp('$pre${_symbol(isLast)}$post');
|
return RegExp('$pre(${_symbol(isLast)})$post');
|
||||||
return match(rgx);
|
|
||||||
// if (isLast) return match(new RegExp(r'.*'));
|
// if (isLast) return match(new RegExp(r'.*'));
|
||||||
// return match(new RegExp(r'[^/]*'));
|
// return match(new RegExp(r'[^/]*'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Parser<Map<String, dynamic>> compile(bool isLast) {
|
Parser<RouteResult> compile(bool isLast) {
|
||||||
return _compile(isLast).map((r) => {});
|
return match(_compile(isLast))
|
||||||
|
.map((r) => RouteResult({}, tail: r.scanner.lastMatch[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Parser<Map<String, dynamic>> compileNext(
|
Parser<RouteResult> compileNext(Parser<RouteResult> p, bool isLast) {
|
||||||
Parser<Map<String, dynamic>> p, bool isLast) {
|
return p.then(compile(isLast)).map((r) {
|
||||||
return p.then(_compile(isLast)).index(0).cast<Map<String, dynamic>>();
|
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
|
@override
|
||||||
Parser<Map<String, dynamic>> compile(bool isLast) {
|
Parser<RouteResult> compile(bool isLast) {
|
||||||
return super.compile(isLast).opt();
|
return super.compile(isLast).opt();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Parser<Map<String, dynamic>> compileNext(
|
Parser<RouteResult> compileNext(Parser<RouteResult> p, bool isLast) {
|
||||||
Parser<Map<String, dynamic>> p, bool isLast) {
|
|
||||||
return p.then(_compile().opt()).map((r) {
|
return p.then(_compile().opt()).map((r) {
|
||||||
if (r.value[1] == null) return r.value[0] as Map<String, dynamic>;
|
if (r.value[1] == null) return r.value[0] as RouteResult;
|
||||||
return (r.value[0] as Map<String, dynamic>)
|
return (r.value[0] as RouteResult)
|
||||||
..addAll({name: Uri.decodeComponent(r.value[1] as String)});
|
..addAll({name: Uri.decodeComponent(r.value[1] as String)});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -240,16 +241,15 @@ class ParameterSegment extends RouteSegment {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Parser<Map<String, dynamic>> compile(bool isLast) {
|
Parser<RouteResult> compile(bool isLast) {
|
||||||
return _compile()
|
return _compile()
|
||||||
.map<Map<String, dynamic>>((r) => {name: Uri.decodeComponent(r.value)});
|
.map((r) => RouteResult({name: Uri.decodeComponent(r.value)}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Parser<Map<String, dynamic>> compileNext(
|
Parser<RouteResult> compileNext(Parser<RouteResult> p, bool isLast) {
|
||||||
Parser<Map<String, dynamic>> p, bool isLast) {
|
|
||||||
return p.then(_compile()).map((r) {
|
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)});
|
..addAll({name: Uri.decodeComponent(r.value[1] as String)});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -273,16 +273,15 @@ class ParsedParameterSegment extends RouteSegment {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Parser<Map<String, dynamic>> compile(bool isLast) {
|
Parser<RouteResult> compile(bool isLast) {
|
||||||
return parameter._compile().map(
|
return parameter._compile().map((r) => RouteResult(
|
||||||
(r) => {parameter.name: getValue(Uri.decodeComponent(r.span.text))});
|
{parameter.name: getValue(Uri.decodeComponent(r.span.text))}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Parser<Map<String, dynamic>> compileNext(
|
Parser<RouteResult> compileNext(Parser<RouteResult> p, bool isLast) {
|
||||||
Parser<Map<String, dynamic>> p, bool isLast) {
|
|
||||||
return p.then(parameter._compile()).map((r) {
|
return p.then(parameter._compile()).map((r) {
|
||||||
return (r.value[0] as Map<String, dynamic>)
|
return (r.value[0] as RouteResult)
|
||||||
..addAll({
|
..addAll({
|
||||||
parameter.name: getValue(Uri.decodeComponent(r.value[1] as String))
|
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 Map<String, Map<String, dynamic>> _cache = {};
|
||||||
final RouteDefinition _routeDefinition;
|
final RouteDefinition _routeDefinition;
|
||||||
String name;
|
String name;
|
||||||
Parser<Map<String, dynamic>> _parser;
|
Parser<RouteResult> _parser;
|
||||||
|
|
||||||
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(new SpanScanner(path.replaceAll(_straySlashes, '')))
|
||||||
.value {
|
.value {
|
||||||
if (_routeDefinition?.segments?.isNotEmpty != true)
|
if (_routeDefinition?.segments?.isNotEmpty != true)
|
||||||
_parser =
|
_parser = match('').map((r) => RouteResult({}));
|
||||||
match<Map<String, dynamic>>('').value((r) => <String, dynamic>{});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
factory Route.join(Route<T> a, Route<T> b) {
|
factory Route.join(Route<T> a, Route<T> b) {
|
||||||
|
@ -26,8 +25,7 @@ class Route<T> {
|
||||||
method: b.method, handlers: b.handlers);
|
method: b.method, handlers: b.handlers);
|
||||||
}
|
}
|
||||||
|
|
||||||
Parser<Map<String, dynamic>> get parser =>
|
Parser<RouteResult> get parser => _parser ??= _routeDefinition.compile();
|
||||||
_parser ??= _routeDefinition.compile();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
|
@ -57,3 +55,23 @@ class Route<T> {
|
||||||
return b.toString();
|
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) {
|
if (parseResult.successful && scanner.isDone) {
|
||||||
var result = new RoutingResult<T>(
|
var result = new RoutingResult<T>(
|
||||||
parseResult: parseResult,
|
parseResult: parseResult,
|
||||||
params: parseResult.value,
|
params: parseResult.value.params,
|
||||||
shallowRoute: route,
|
shallowRoute: route,
|
||||||
shallowRouter: this);
|
shallowRouter: this,
|
||||||
|
tail: (parseResult.value.tail ?? '') + scanner.rest);
|
||||||
out.add(result);
|
out.add(result);
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ part of angel_route.src.router;
|
||||||
/// Represents a complex result of navigating to a path.
|
/// Represents a complex result of navigating to a path.
|
||||||
class RoutingResult<T> {
|
class RoutingResult<T> {
|
||||||
/// The parse result that matched the given sub-path.
|
/// 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.
|
/// A nested instance, if a sub-path was matched.
|
||||||
final Iterable<RoutingResult<T>> nested;
|
final Iterable<RoutingResult<T>> nested;
|
||||||
|
@ -85,7 +85,7 @@ class RoutingResult<T> {
|
||||||
this.nested,
|
this.nested,
|
||||||
this.shallowRoute,
|
this.shallowRoute,
|
||||||
this.shallowRouter,
|
this.shallowRouter,
|
||||||
this.tail}) {
|
@required this.tail}) {
|
||||||
this.params.addAll(params ?? {});
|
this.params.addAll(params ?? {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
name: angel_route
|
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.
|
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>
|
author: Tobe O <thosakwe@gmail.com>
|
||||||
homepage: https://github.com/angel-dart/angel_route
|
homepage: https://github.com/angel-dart/angel_route
|
||||||
environment:
|
environment:
|
||||||
|
|
|
@ -22,4 +22,25 @@ void main() {
|
||||||
router.resolveAbsolute('/isnt/she/fierce%20harmonica%solo').first;
|
router.resolveAbsolute('/isnt/she/fierce%20harmonica%solo').first;
|
||||||
expect(result.handlers, ['lovely']);
|
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