Use Optional

This commit is contained in:
thomashii@dukefirehawk.com 2021-05-11 17:03:52 +08:00
parent 15926ff45d
commit 25af334f4d
27 changed files with 78 additions and 69 deletions

View file

@ -18,7 +18,7 @@ final Parser<Map<String, String>> credentials = chain<String>([
match<String>(':'), match<String>(':'),
string.opt(), string.opt(),
]).map<Map<String, String>>( ]).map<Map<String, String>>(
(r) => {'username': r.value![0]!, 'password': r.value![2]!}); (r) => {'username': r.value![0], 'password': r.value![2]});
/// We can actually embed a parser within another parser. /// We can actually embed a parser within another parser.
/// ///

View file

@ -24,7 +24,7 @@ Parser<num> calculatorGrammar() {
expr.space(), expr.space(),
match<Null>(op).space() as Parser<num>, match<Null>(op).space() as Parser<num>,
expr.space(), expr.space(),
]).map((r) => f(r.value![0]!, r.value![2]!)), ]).map((r) => f(r.value![0], r.value![2])),
); );
} }

View file

@ -7,7 +7,7 @@ class _Advance<T> extends Parser<T> {
_Advance(this.parser, this.amount); _Advance(this.parser, this.amount);
@override @override
ParseResult<T?> __parse(ParseArgs args) { ParseResult<T> __parse(ParseArgs args) {
var result = parser._parse(args.increaseDepth()).change(parser: this); var result = parser._parse(args.increaseDepth()).change(parser: this);
if (result.successful) args.scanner.position += amount; if (result.successful) args.scanner.position += amount;
return result; return result;

View file

@ -21,7 +21,7 @@ class _Any<T> extends Parser<T> {
_Any(this.parsers, this.backtrack, this.errorMessage, this.severity); _Any(this.parsers, this.backtrack, this.errorMessage, this.severity);
@override @override
ParseResult<T?> _parse(ParseArgs args) { ParseResult<T> _parse(ParseArgs args) {
var inactive = parsers var inactive = parsers
.where((p) => !args.trampoline.isActive(p, args.scanner.position)); .where((p) => !args.trampoline.isActive(p, args.scanner.position));

View file

@ -1,13 +1,13 @@
part of lex.src.combinator; part of lex.src.combinator;
class _Cache<T> extends Parser<T> { class _Cache<T> extends Parser<T> {
final Map<int, ParseResult<T?>> _cache = {}; final Map<int, ParseResult<T>> _cache = {};
final Parser<T> parser; final Parser<T> parser;
_Cache(this.parser); _Cache(this.parser);
@override @override
ParseResult<T?> __parse(ParseArgs args) { ParseResult<T> __parse(ParseArgs args) {
return _cache.putIfAbsent(args.scanner.position, () { return _cache.putIfAbsent(args.scanner.position, () {
return parser._parse(args.increaseDepth()); return parser._parse(args.increaseDepth());
}).change(parser: this); }).change(parser: this);

View file

@ -3,9 +3,9 @@ part of lex.src.combinator;
/// Expects to parse a sequence of [parsers]. /// Expects to parse a sequence of [parsers].
/// ///
/// If [failFast] is `true` (default), then the first failure to parse will abort the parse. /// If [failFast] is `true` (default), then the first failure to parse will abort the parse.
ListParser<T?> chain<T>(Iterable<Parser<T>> parsers, ListParser<T> chain<T>(Iterable<Parser<T>> parsers,
{bool failFast: true, SyntaxErrorSeverity? severity}) { {bool failFast: true, SyntaxErrorSeverity? severity}) {
return _Chain<T?>( return _Chain<T>(
parsers, failFast != false, severity ?? SyntaxErrorSeverity.error); parsers, failFast != false, severity ?? SyntaxErrorSeverity.error);
} }
@ -17,7 +17,7 @@ class _Alt<T> extends Parser<T> {
_Alt(this.parser, this.errorMessage, this.severity); _Alt(this.parser, this.errorMessage, this.severity);
@override @override
ParseResult<T?> __parse(ParseArgs args) { ParseResult<T> __parse(ParseArgs args) {
var result = parser._parse(args.increaseDepth()); var result = parser._parse(args.increaseDepth());
return result.successful return result.successful
? result ? result
@ -33,7 +33,7 @@ class _Alt<T> extends Parser<T> {
} }
} }
class _Chain<T> extends ListParser<T?> { class _Chain<T> extends ListParser<T> {
final Iterable<Parser<T>> parsers; final Iterable<Parser<T>> parsers;
final bool failFast; final bool failFast;
final SyntaxErrorSeverity severity; final SyntaxErrorSeverity severity;
@ -41,7 +41,7 @@ class _Chain<T> extends ListParser<T?> {
_Chain(this.parsers, this.failFast, this.severity); _Chain(this.parsers, this.failFast, this.severity);
@override @override
ParseResult<List<T?>?> __parse(ParseArgs args) { ParseResult<List<T>> __parse(ParseArgs args) {
var errors = <SyntaxError>[]; var errors = <SyntaxError>[];
var results = <T?>[]; var results = <T?>[];
var spans = <FileSpan>[]; var spans = <FileSpan>[];
@ -61,7 +61,10 @@ class _Chain<T> extends ListParser<T?> {
successful = false; successful = false;
} }
//TODO: To be looked at
//if (result.value != null) {
results.add(result.value); results.add(result.value);
//}
if (result.span != null) { if (result.span != null) {
spans.add(result.span!); spans.add(result.span!);
@ -74,14 +77,14 @@ class _Chain<T> extends ListParser<T?> {
span = spans.reduce((a, b) => a.expand(b)); span = spans.reduce((a, b) => a.expand(b));
} }
return ParseResult<List<T?>?>( return ParseResult<List<T>>(
args.trampoline, args.trampoline,
args.scanner, args.scanner,
this, this,
successful, successful,
errors, errors,
span: span, span: span,
value: List<T?>.unmodifiable(results), value: List<T>.unmodifiable(results),
); );
} }

View file

@ -9,7 +9,7 @@ class _Check<T> extends Parser<T> {
_Check(this.parser, this.matcher, this.errorMessage, this.severity); _Check(this.parser, this.matcher, this.errorMessage, this.severity);
@override @override
ParseResult<T?> __parse(ParseArgs args) { ParseResult<T> __parse(ParseArgs args) {
var matchState = {}; var matchState = {};
var result = parser._parse(args.increaseDepth()).change(parser: this); var result = parser._parse(args.increaseDepth()).change(parser: this);
if (!result.successful) if (!result.successful)

View file

@ -7,6 +7,7 @@ import 'package:matcher/matcher.dart';
import 'package:source_span/source_span.dart'; import 'package:source_span/source_span.dart';
import 'package:string_scanner/string_scanner.dart'; import 'package:string_scanner/string_scanner.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
import 'package:optional/optional.dart';
import '../error.dart'; import '../error.dart';
part 'any.dart'; part 'any.dart';
@ -67,9 +68,9 @@ class ParseArgs {
/// A parser combinator, which can parse very complicated grammars in a manageable manner. /// A parser combinator, which can parse very complicated grammars in a manageable manner.
abstract class Parser<T> { abstract class Parser<T> {
ParseResult<T?> __parse(ParseArgs args); ParseResult<T> __parse(ParseArgs args);
ParseResult<T?> _parse(ParseArgs args) { ParseResult<T> _parse(ParseArgs args) {
var pos = args.scanner.position; var pos = args.scanner.position;
if (args.trampoline.hasMemoized(this, pos)) if (args.trampoline.hasMemoized(this, pos))
@ -86,7 +87,7 @@ abstract class Parser<T> {
} }
/// Parses text from a [SpanScanner]. /// Parses text from a [SpanScanner].
ParseResult<T?> parse(SpanScanner scanner, [int depth = 1]) { ParseResult<T> parse(SpanScanner scanner, [int depth = 1]) {
var args = ParseArgs(Trampoline(), scanner, depth); var args = ParseArgs(Trampoline(), scanner, depth);
return _parse(args); return _parse(args);
} }
@ -105,7 +106,7 @@ abstract class Parser<T> {
// TODO: Type issue // TODO: Type issue
/// Runs the given function, which changes the returned [ParseResult] into one relating to a [U] object. /// Runs the given function, which changes the returned [ParseResult] into one relating to a [U] object.
Parser<U> change<U>(ParseResult<U?> Function(ParseResult<T?>) f) { Parser<U> change<U>(ParseResult<U> Function(ParseResult<T>) f) {
return _Change<T, U>(this, f); return _Change<T, U>(this, f);
} }
@ -128,7 +129,7 @@ abstract class Parser<T> {
} }
/// Transforms the parse result using a unary function. /// Transforms the parse result using a unary function.
Parser<U> map<U>(U Function(ParseResult<T?>) f) { Parser<U> map<U>(U Function(ParseResult<T>) f) {
return _Map<T, U>(this, f); return _Map<T, U>(this, f);
} }
@ -171,7 +172,7 @@ abstract class Parser<T> {
Parser<T> or<U>(Parser<T> other) => any<T>([this, other]); Parser<T> or<U>(Parser<T> other) => any<T>([this, other]);
/// Parses this sequence one or more times. /// Parses this sequence one or more times.
ListParser<T?> plus() => times(1, exact: false); ListParser<T> plus() => times(1, exact: false);
/// Safely escapes this parser when an error occurs. /// Safely escapes this parser when an error occurs.
/// ///
@ -207,11 +208,11 @@ abstract class Parser<T> {
}); });
} }
Parser<T?> surroundedByCurlyBraces({T? defaultValue}) => opt() Parser<T> surroundedByCurlyBraces({required T defaultValue}) => opt()
.surroundedBy(match('{').space(), match('}').space()) .surroundedBy(match('{').space(), match('}').space())
.map((r) => r.value ?? defaultValue); .map((r) => r.value ?? defaultValue);
Parser<T?> surroundedBySquareBrackets({T? defaultValue}) => opt() Parser<T> surroundedBySquareBrackets({required T defaultValue}) => opt()
.surroundedBy(match('[').space(), match(']').space()) .surroundedBy(match('[').space(), match(']').space())
.map((r) => r.value ?? defaultValue); .map((r) => r.value ?? defaultValue);
@ -336,7 +337,9 @@ class Trampoline {
} }
bool isActive(Parser parser, int position) { bool isActive(Parser parser, int position) {
if (!_active.containsKey(parser)) return false; if (!_active.containsKey(parser)) {
return false;
}
var q = _active[parser]!; var q = _active[parser]!;
if (q.isEmpty) return false; if (q.isEmpty) return false;
//return q.contains(position); //return q.contains(position);

View file

@ -7,8 +7,8 @@ class _Compare<T> extends ListParser<T> {
_Compare(this.parser, this.compare); _Compare(this.parser, this.compare);
@override @override
ParseResult<List<T>?> __parse(ParseArgs args) { ParseResult<List<T>> __parse(ParseArgs args) {
ParseResult<List<T>?> result = parser._parse(args.increaseDepth()); ParseResult<List<T>> result = parser._parse(args.increaseDepth());
if (!result.successful) return result; if (!result.successful) return result;
result = result.change( result = result.change(

View file

@ -7,7 +7,7 @@ class _FoldErrors<T> extends Parser<T> {
_FoldErrors(this.parser, this.equal); _FoldErrors(this.parser, this.equal);
@override @override
ParseResult<T?> __parse(ParseArgs args) { ParseResult<T> __parse(ParseArgs args) {
var result = parser._parse(args.increaseDepth()).change(parser: this); var result = parser._parse(args.increaseDepth()).change(parser: this);
var errors = result.errors.fold<List<SyntaxError>>([], (out, e) { var errors = result.errors.fold<List<SyntaxError>>([], (out, e) {
if (!out.any((b) => equal(e, b))) out.add(e); if (!out.any((b) => equal(e, b))) out.add(e);

View file

@ -16,7 +16,7 @@ class _Longest<T> extends Parser<T> {
_Longest(this.parsers, this.errorMessage, this.severity); _Longest(this.parsers, this.errorMessage, this.severity);
@override @override
ParseResult<T?> _parse(ParseArgs args) { ParseResult<T> _parse(ParseArgs args) {
var inactive = parsers var inactive = parsers
.toList() .toList()
.where((p) => !args.trampoline.isActive(p, args.scanner.position)); .where((p) => !args.trampoline.isActive(p, args.scanner.position));
@ -27,7 +27,7 @@ class _Longest<T> extends Parser<T> {
int replay = args.scanner.position; int replay = args.scanner.position;
var errors = <SyntaxError>[]; var errors = <SyntaxError>[];
var results = <ParseResult<T?>>[]; var results = <ParseResult<T>>[];
for (var parser in inactive) { for (var parser in inactive) {
var result = parser._parse(args.increaseDepth()); var result = parser._parse(args.increaseDepth());
@ -59,10 +59,10 @@ class _Longest<T> extends Parser<T> {
} }
@override @override
ParseResult<T?> __parse(ParseArgs args) { ParseResult<T> __parse(ParseArgs args) {
int replay = args.scanner.position; int replay = args.scanner.position;
var errors = <SyntaxError>[]; var errors = <SyntaxError>[];
var results = <ParseResult<T?>>[]; var results = <ParseResult<T>>[];
for (var parser in parsers) { for (var parser in parsers) {
var result = parser._parse(args.increaseDepth()); var result = parser._parse(args.increaseDepth());

View file

@ -2,14 +2,14 @@ part of lex.src.combinator;
class _Map<T, U> extends Parser<U> { class _Map<T, U> extends Parser<U> {
final Parser<T> parser; final Parser<T> parser;
final U Function(ParseResult<T?>) f; final U Function(ParseResult<T>) f;
_Map(this.parser, this.f); _Map(this.parser, this.f);
@override @override
ParseResult<U?> __parse(ParseArgs args) { ParseResult<U> __parse(ParseArgs args) {
var result = parser._parse(args.increaseDepth()); var result = parser._parse(args.increaseDepth());
return ParseResult<U?>( return ParseResult<U>(
args.trampoline, args.trampoline,
args.scanner, args.scanner,
this, this,
@ -34,12 +34,12 @@ class _Map<T, U> extends Parser<U> {
class _Change<T, U> extends Parser<U> { class _Change<T, U> extends Parser<U> {
final Parser<T> parser; final Parser<T> parser;
final ParseResult<U?> Function(ParseResult<T?>) f; final ParseResult<U> Function(ParseResult<T>) f;
_Change(this.parser, this.f); _Change(this.parser, this.f);
@override @override
ParseResult<U?> __parse(ParseArgs args) { ParseResult<U> __parse(ParseArgs args) {
return f(parser._parse(args.increaseDepth())).change(parser: this); return f(parser._parse(args.increaseDepth())).change(parser: this);
} }

View file

@ -7,7 +7,7 @@ class _MaxDepth<T> extends Parser<T> {
_MaxDepth(this.parser, this.cap); _MaxDepth(this.parser, this.cap);
@override @override
ParseResult<T?> __parse(ParseArgs args) { ParseResult<T> __parse(ParseArgs args) {
if (args.depth > cap) { if (args.depth > cap) {
return ParseResult<T>(args.trampoline, args.scanner, this, false, []); return ParseResult<T>(args.trampoline, args.scanner, this, false, []);
} }

View file

@ -8,7 +8,7 @@ class _Negate<T> extends Parser<T> {
_Negate(this.parser, this.errorMessage, this.severity); _Negate(this.parser, this.errorMessage, this.severity);
@override @override
ParseResult<T?> __parse(ParseArgs args) { ParseResult<T> __parse(ParseArgs args) {
var result = parser._parse(args.increaseDepth()).change(parser: this); var result = parser._parse(args.increaseDepth()).change(parser: this);
if (!result.successful) { if (!result.successful) {

View file

@ -7,7 +7,7 @@ class _Opt<T> extends Parser<T> {
_Opt(this.parser, this.backtrack); _Opt(this.parser, this.backtrack);
@override @override
ParseResult<T?> __parse(ParseArgs args) { ParseResult<T> __parse(ParseArgs args) {
var replay = args.scanner.position; var replay = args.scanner.position;
var result = parser._parse(args.increaseDepth()); var result = parser._parse(args.increaseDepth());
@ -35,9 +35,9 @@ class _ListOpt<T> extends ListParser<T> {
_ListOpt(this.parser, this.backtrack); _ListOpt(this.parser, this.backtrack);
@override @override
ParseResult<List<T>?> __parse(ParseArgs args) { ParseResult<List<T>> __parse(ParseArgs args) {
var replay = args.scanner.position; var replay = args.scanner.position;
ParseResult<List<T>?> result = parser._parse(args.increaseDepth()); ParseResult<List<T>> result = parser._parse(args.increaseDepth());
if (!result.successful) args.scanner.position = replay; if (!result.successful) args.scanner.position = replay;

View file

@ -7,8 +7,8 @@ class _Reduce<T> extends Parser<T> {
_Reduce(this.parser, this.combine); _Reduce(this.parser, this.combine);
@override @override
ParseResult<T?> __parse(ParseArgs args) { ParseResult<T> __parse(ParseArgs args) {
ParseResult<List<T>?> result = parser._parse(args.increaseDepth()); ParseResult<List<T>> result = parser._parse(args.increaseDepth());
if (!result.successful) if (!result.successful)
return ParseResult<T>( return ParseResult<T>(

View file

@ -15,14 +15,14 @@ class Reference<T> extends Parser<T> {
} }
@override @override
ParseResult<T?> __parse(ParseArgs args) { ParseResult<T> __parse(ParseArgs args) {
if (_parser == null) if (_parser == null)
throw StateError('There is no parser assigned to this reference.'); throw StateError('There is no parser assigned to this reference.');
return _parser!._parse(args); return _parser!._parse(args);
} }
@override @override
ParseResult<T?> _parse(ParseArgs args) { ParseResult<T> _parse(ParseArgs args) {
if (_parser == null) if (_parser == null)
throw StateError('There is no parser assigned to this reference.'); throw StateError('There is no parser assigned to this reference.');
return _parser!._parse(args); return _parser!._parse(args);

View file

@ -12,12 +12,12 @@ class _Repeat<T> extends ListParser<T> {
this.backtrack, this.severity); this.backtrack, this.severity);
@override @override
ParseResult<List<T>?> __parse(ParseArgs args) { ParseResult<List<T>> __parse(ParseArgs args) {
var errors = <SyntaxError>[]; var errors = <SyntaxError>[];
var results = <T>[]; var results = <T>[];
var spans = <FileSpan>[]; var spans = <FileSpan>[];
int success = 0, replay = args.scanner.position; int success = 0, replay = args.scanner.position;
ParseResult<T?> result; ParseResult<T> result;
do { do {
result = parser._parse(args.increaseDepth()); result = parser._parse(args.increaseDepth());
@ -51,7 +51,7 @@ class _Repeat<T> extends ListParser<T> {
} else if (success > count && exact) { } else if (success > count && exact) {
if (backtrack) args.scanner.position = replay; if (backtrack) args.scanner.position = replay;
return ParseResult<List<T>?>(args.trampoline, args.scanner, this, false, [ return ParseResult<List<T>>(args.trampoline, args.scanner, this, false, [
SyntaxError( SyntaxError(
severity, severity,
tooMany, tooMany,

View file

@ -10,7 +10,7 @@ class _Safe<T> extends Parser<T> {
_Safe(this.parser, this.backtrack, this.errorMessage, this.severity); _Safe(this.parser, this.backtrack, this.errorMessage, this.severity);
@override @override
ParseResult<T?> __parse(ParseArgs args) { ParseResult<T> __parse(ParseArgs args) {
var replay = args.scanner.position; var replay = args.scanner.position;
try { try {

View file

@ -2,12 +2,12 @@ part of lex.src.combinator;
class _Value<T> extends Parser<T> { class _Value<T> extends Parser<T> {
final Parser<T> parser; final Parser<T> parser;
final T Function(ParseResult<T?>) f; final T Function(ParseResult<T>) f;
_Value(this.parser, this.f); _Value(this.parser, this.f);
@override @override
ParseResult<T?> __parse(ParseArgs args) { ParseResult<T> __parse(ParseArgs args) {
var result = parser._parse(args.increaseDepth()).change(parser: this); var result = parser._parse(args.increaseDepth()).change(parser: this);
return result.successful ? result.change(value: f(result)) : result; return result.successful ? result.change(value: f(result)) : result;
} }

View file

@ -15,5 +15,6 @@ dependencies:
source_span: ^1.8.1 source_span: ^1.8.1
string_scanner: ^1.1.0 string_scanner: ^1.1.0
tuple: ^2.0.0 tuple: ^2.0.0
optional: ^6.0.0-nullsafety.2
dev_dependencies: dev_dependencies:
test: ^1.17.3 test: ^1.17.3

View file

@ -11,11 +11,11 @@ main() {
var numbers = number.plus(); var numbers = number.plus();
test('sort', () { test('sort', () {
var parser = numbers.sort((a, b) => a!.compareTo(b!)); var parser = numbers.sort((a, b) => a.compareTo(b));
expect(parser.parse(scan('21,2,3,34,20')).value, [2, 3, 20, 21, 34]); expect(parser.parse(scan('21,2,3,34,20')).value, [2, 3, 20, 21, 34]);
}); });
test('reduce', () { test('reduce', () {
var parser = numbers.reduce((a, b) => a! + b!); var parser = numbers.reduce((a, b) => a + b);
expect(parser.parse(scan('21,2,3,34,20')).value, 80); expect(parser.parse(scan('21,2,3,34,20')).value, 80);
expect(parser.parse(scan('not numbers')).value, isNull); expect(parser.parse(scan('not numbers')).value, isNull);
}); });

View file

@ -139,7 +139,8 @@ abstract class Driver<
pipeline.handlers, pipeline.handlers,
resolved.fold<Map<String, dynamic>>( resolved.fold<Map<String, dynamic>>(
<String, dynamic>{}, (out, r) => out..addAll(r.allParams)), <String, dynamic>{}, (out, r) => out..addAll(r.allParams)),
(resolved.isEmpty ? null : resolved.first.parseResult)!, //(resolved.isEmpty ? null : resolved.first.parseResult),
resolved.first.parseResult,
pipeline, pipeline,
); );
} }

View file

@ -22,10 +22,11 @@ dependencies:
ref: sdk-2.12.x_nnbd ref: sdk-2.12.x_nnbd
path: packages/model path: packages/model
angel_route: angel_route:
git: path: ../route
url: https://github.com/dukefirehawk/angel.git # git:
ref: sdk-2.12.x_nnbd # url: https://github.com/dukefirehawk/angel.git
path: packages/route # ref: sdk-2.12.x_nnbd
# path: packages/route
charcode: ^1.2.0 charcode: ^1.2.0
combinator: combinator:
git: git:

View file

@ -311,7 +311,7 @@ class Router<T> {
if (parseResult != null) { if (parseResult != null) {
if (parseResult.successful && scanner.isDone) { if (parseResult.successful && scanner.isDone) {
var tailResult = parseResult.value?.tail ?? ''; var tailResult = parseResult.value?.tail ?? '';
print(tailResult); //print(tailResult);
var result = RoutingResult<T>( var result = RoutingResult<T>(
parseResult: parseResult, parseResult: parseResult,
params: parseResult.value!.params, params: parseResult.value!.params,
@ -334,13 +334,13 @@ class Router<T> {
/// Returns the result of [resolve] with [path] passed as /// Returns the result of [resolve] with [path] passed as
/// both `absolute` and `relative`. /// both `absolute` and `relative`.
Iterable<RoutingResult<T?>> resolveAbsolute(String path, Iterable<RoutingResult<T>> resolveAbsolute(String path,
{String method = 'GET', bool strip = true}) => {String method = 'GET', bool strip = true}) =>
resolveAll(path, path, method: method, strip: strip); resolveAll(path, path, method: method, strip: strip);
/// Finds every possible [Route] that matches the given path, /// Finds every possible [Route] that matches the given path,
/// with the given method. /// with the given method.
Iterable<RoutingResult<T?>> resolveAll(String absolute, String relative, Iterable<RoutingResult<T>> resolveAll(String absolute, String relative,
{String method = 'GET', bool strip = true}) { {String method = 'GET', bool strip = true}) {
if (_useCache == true) { if (_useCache == true) {
return _cache.putIfAbsent('$method$absolute', return _cache.putIfAbsent('$method$absolute',

View file

@ -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<RouteResult?> 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;
@ -47,10 +47,10 @@ class RoutingResult<T> {
} }
/// All handlers on this sub-path and its children. /// All handlers on this sub-path and its children.
List<T?> get allHandlers { List<T> get allHandlers {
final handlers = <T?>[]; final handlers = <T>[];
void crawl(RoutingResult<T?> result) { void crawl(RoutingResult<T> result) {
handlers.addAll(result.handlers); handlers.addAll(result.handlers);
if (result.nested.isNotEmpty == true) { if (result.nested.isNotEmpty == true) {

View file

@ -7,11 +7,11 @@ environment:
sdk: '>=2.12.0 <3.0.0' sdk: '>=2.12.0 <3.0.0'
dependencies: dependencies:
combinator: combinator:
# path: ../combinator path: ../combinator
git: # git:
url: https://github.com/dukefirehawk/angel.git # url: https://github.com/dukefirehawk/angel.git
ref: sdk-2.12.x_nnbd # ref: sdk-2.12.x_nnbd
path: packages/combinator # path: packages/combinator
string_scanner: ^1.0.0 string_scanner: ^1.0.0
dev_dependencies: dev_dependencies:
build_runner: ^1.11.5 build_runner: ^1.11.5