Update rgx parser

This commit is contained in:
Tobe O 2018-08-20 10:24:11 -04:00
parent 1c5e572688
commit 951c593d58
8 changed files with 99 additions and 27 deletions

View file

@ -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
View file

@ -0,0 +1,3 @@
# 3.0.0-alpha
* Make `Router` and `Route` single-parameter generic.
* Remove `package:browser` dependency.

View file

@ -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;

View file

@ -1,2 +1,3 @@
analyzer:
strong-mode: true
strong-mode:
implicit-casts: false

View file

@ -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]))});
});
}
}

View file

@ -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
View 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);
});
}

View file

@ -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']));
});
});
});