Update rgx parser
This commit is contained in:
parent
1c5e572688
commit
951c593d58
8 changed files with 99 additions and 27 deletions
|
@ -2,6 +2,7 @@
|
|||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
|
|
3
CHANGELOG.md
Normal file
3
CHANGELOG.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# 3.0.0-alpha
|
||||
* Make `Router` and `Route` single-parameter generic.
|
||||
* Remove `package:browser` dependency.
|
|
@ -46,6 +46,13 @@ main() {
|
|||
return { 'result': pow(int.parse(n), 0.5) };
|
||||
});
|
||||
|
||||
// You can also have parameters auto-parsed.
|
||||
//
|
||||
// Supports int, double, and num.
|
||||
router.get('/square_root/int:id([0-9]+)', (int n) {
|
||||
return { 'result': pow(n, 0.5) };
|
||||
});
|
||||
|
||||
router.group('/show/:id', (router) {
|
||||
router.get('/reviews', (id) {
|
||||
return someQuery(id).reviews;
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
analyzer:
|
||||
strong-mode: true
|
||||
strong-mode:
|
||||
implicit-casts: false
|
|
@ -3,7 +3,10 @@ part of angel_route.src.router;
|
|||
class RouteGrammar {
|
||||
static final Parser<String> notSlash =
|
||||
match(new RegExp(r'[^/]+')).value((r) => r.span.text);
|
||||
static final Parser<RegExp> regExp = new _RegExpParser();
|
||||
|
||||
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_]+)'))
|
||||
.value((r) => r.span.text.substring(1));
|
||||
|
@ -17,14 +20,27 @@ class RouteGrammar {
|
|||
return r.value[1] == true ? new OptionalSegment(s) : s;
|
||||
});
|
||||
|
||||
static final Parser<ParsedParameterSegment> parsedParameterSegment = chain([
|
||||
match(new RegExp(r'(int|num|double)'),
|
||||
errorMessage: 'Expected "int","double", or "num".')
|
||||
.map((r) => r.span.text),
|
||||
parameterSegment,
|
||||
]).map((r) {
|
||||
return new ParsedParameterSegment(r.value[0], r.value[1]);
|
||||
});
|
||||
|
||||
static final Parser<WildcardSegment> wildcardSegment =
|
||||
match('*').value((r) => new WildcardSegment());
|
||||
|
||||
static final Parser<ConstantSegment> constantSegment =
|
||||
notSlash.map((r) => new ConstantSegment(r.value));
|
||||
|
||||
static final Parser<RouteSegment> routeSegment =
|
||||
any([parameterSegment, wildcardSegment, constantSegment]);
|
||||
static final Parser<RouteSegment> routeSegment = any([
|
||||
parsedParameterSegment,
|
||||
parameterSegment,
|
||||
wildcardSegment,
|
||||
constantSegment
|
||||
]);
|
||||
|
||||
static final Parser<RouteDefinition> routeDefinition = routeSegment
|
||||
.separatedBy(match('/'))
|
||||
|
@ -32,17 +48,6 @@ class RouteGrammar {
|
|||
.surroundedBy(match('/').star().opt());
|
||||
}
|
||||
|
||||
class _RegExpParser extends Parser<RegExp> {
|
||||
static final RegExp rgx = new RegExp(r'\((.+)\)');
|
||||
|
||||
@override
|
||||
ParseResult<RegExp> parse(SpanScanner scanner, [int depth = 1]) {
|
||||
if (!scanner.matches(rgx)) return new ParseResult(this, false, []);
|
||||
return new ParseResult(this, true, [],
|
||||
span: scanner.lastSpan, value: new RegExp(scanner.lastMatch[1]));
|
||||
}
|
||||
}
|
||||
|
||||
class RouteDefinition {
|
||||
final List<RouteSegment> segments;
|
||||
|
||||
|
@ -66,6 +71,7 @@ class RouteDefinition {
|
|||
|
||||
abstract class RouteSegment {
|
||||
Parser<Map<String, dynamic>> compile(bool isLast);
|
||||
|
||||
Parser<Map<String, dynamic>> compileNext(
|
||||
Parser<Map<String, dynamic>> p, bool isLast);
|
||||
}
|
||||
|
@ -171,3 +177,36 @@ class ParameterSegment extends RouteSegment {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
class ParsedParameterSegment extends RouteSegment {
|
||||
final String type;
|
||||
final ParameterSegment parameter;
|
||||
|
||||
ParsedParameterSegment(this.type, this.parameter);
|
||||
|
||||
num getValue(String s) {
|
||||
switch (type) {
|
||||
case 'int':
|
||||
return int.parse(s);
|
||||
case 'double':
|
||||
return double.parse(s);
|
||||
default:
|
||||
return num.parse(s);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Parser<Map<String, dynamic>> compile(bool isLast) {
|
||||
return parameter._compile().map(
|
||||
(r) => {parameter.name: getValue(Uri.decodeComponent(r.span.text))});
|
||||
}
|
||||
|
||||
@override
|
||||
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]))});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
13
pubspec.yaml
13
pubspec.yaml
|
@ -1,13 +1,14 @@
|
|||
name: angel_route
|
||||
description: A powerful, isomorphic routing library for Dart.
|
||||
version: 2.0.4
|
||||
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
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/angel_route
|
||||
environment:
|
||||
sdk: ">=1.19.0"
|
||||
sdk: ">=2.0.0-dev <3.0.0"
|
||||
dependencies:
|
||||
combinator: ^1.0.0-beta
|
||||
combinator: ^1.0.0
|
||||
dev_dependencies:
|
||||
browser: ">=0.10.0 < 0.11.0"
|
||||
build_runner: ^0.10.0
|
||||
build_web_compilers: ^0.4.0
|
||||
http: ">=0.11.3 <0.12.0"
|
||||
test: ">=0.12.15 <0.13.0"
|
||||
test: ^1.0.0
|
20
test/parse_test.dart
Normal file
20
test/parse_test.dart
Normal file
|
@ -0,0 +1,20 @@
|
|||
import 'package:angel_route/angel_route.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
var router = new Router()
|
||||
..get('/int/int:id', '')
|
||||
..get('/double/double:id', '')
|
||||
..get('/num/num:id', '');
|
||||
|
||||
num getId(String path) {
|
||||
var result = router.resolveAbsolute(path).first;
|
||||
return result.allParams['id'];
|
||||
}
|
||||
|
||||
test('parse', () {
|
||||
expect(getId('/int/2'), 2);
|
||||
expect(getId('/double/2.0'), 2.0);
|
||||
expect(getId('/num/-2.4'), -2.4);
|
||||
});
|
||||
}
|
|
@ -27,7 +27,7 @@ main() {
|
|||
|
||||
router.group('/people', (router) {
|
||||
router.get('/', (req, res) {
|
||||
res.write(JSON.encode(people));
|
||||
res.write(json.encode(people));
|
||||
return false;
|
||||
});
|
||||
|
||||
|
@ -35,14 +35,14 @@ main() {
|
|||
router.get('/', (req, res) {
|
||||
// In a real application, we would take the param,
|
||||
// but not here...
|
||||
res.write(JSON.encode(people.first));
|
||||
res.write(json.encode(people.first));
|
||||
return false;
|
||||
});
|
||||
|
||||
router.get('/name', (req, res) {
|
||||
// In a real application, we would take the param,
|
||||
// but not here...
|
||||
res.write(JSON.encode(people.first['name']));
|
||||
res.write(json.encode(people.first['name']));
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
@ -129,20 +129,20 @@ main() {
|
|||
test('root', () async {
|
||||
final res = await client.get('$url/people');
|
||||
print('Response: ${res.body}');
|
||||
expect(JSON.decode(res.body), equals(people));
|
||||
expect(json.decode(res.body), equals(people));
|
||||
});
|
||||
|
||||
group('param', () {
|
||||
test('root', () async {
|
||||
final res = await client.get('$url/people/0');
|
||||
print('Response: ${res.body}');
|
||||
expect(JSON.decode(res.body), equals(people.first));
|
||||
expect(json.decode(res.body), equals(people.first));
|
||||
});
|
||||
|
||||
test('path', () async {
|
||||
final res = await client.get('$url/people/0/name');
|
||||
print('Response: ${res.body}');
|
||||
expect(JSON.decode(res.body), equals(people.first['name']));
|
||||
expect(json.decode(res.body), equals(people.first['name']));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue