Use Optional
This commit is contained in:
parent
15926ff45d
commit
25af334f4d
27 changed files with 78 additions and 69 deletions
|
@ -18,7 +18,7 @@ final Parser<Map<String, String>> credentials = chain<String>([
|
|||
match<String>(':'),
|
||||
string.opt(),
|
||||
]).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.
|
||||
///
|
||||
|
|
|
@ -24,7 +24,7 @@ Parser<num> calculatorGrammar() {
|
|||
expr.space(),
|
||||
match<Null>(op).space() as Parser<num>,
|
||||
expr.space(),
|
||||
]).map((r) => f(r.value![0]!, r.value![2]!)),
|
||||
]).map((r) => f(r.value![0], r.value![2])),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ class _Advance<T> extends Parser<T> {
|
|||
_Advance(this.parser, this.amount);
|
||||
|
||||
@override
|
||||
ParseResult<T?> __parse(ParseArgs args) {
|
||||
ParseResult<T> __parse(ParseArgs args) {
|
||||
var result = parser._parse(args.increaseDepth()).change(parser: this);
|
||||
if (result.successful) args.scanner.position += amount;
|
||||
return result;
|
||||
|
|
|
@ -21,7 +21,7 @@ class _Any<T> extends Parser<T> {
|
|||
_Any(this.parsers, this.backtrack, this.errorMessage, this.severity);
|
||||
|
||||
@override
|
||||
ParseResult<T?> _parse(ParseArgs args) {
|
||||
ParseResult<T> _parse(ParseArgs args) {
|
||||
var inactive = parsers
|
||||
.where((p) => !args.trampoline.isActive(p, args.scanner.position));
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
part of lex.src.combinator;
|
||||
|
||||
class _Cache<T> extends Parser<T> {
|
||||
final Map<int, ParseResult<T?>> _cache = {};
|
||||
final Map<int, ParseResult<T>> _cache = {};
|
||||
final Parser<T> parser;
|
||||
|
||||
_Cache(this.parser);
|
||||
|
||||
@override
|
||||
ParseResult<T?> __parse(ParseArgs args) {
|
||||
ParseResult<T> __parse(ParseArgs args) {
|
||||
return _cache.putIfAbsent(args.scanner.position, () {
|
||||
return parser._parse(args.increaseDepth());
|
||||
}).change(parser: this);
|
||||
|
|
|
@ -3,9 +3,9 @@ part of lex.src.combinator;
|
|||
/// Expects to parse a sequence of [parsers].
|
||||
///
|
||||
/// 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}) {
|
||||
return _Chain<T?>(
|
||||
return _Chain<T>(
|
||||
parsers, failFast != false, severity ?? SyntaxErrorSeverity.error);
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ class _Alt<T> extends Parser<T> {
|
|||
_Alt(this.parser, this.errorMessage, this.severity);
|
||||
|
||||
@override
|
||||
ParseResult<T?> __parse(ParseArgs args) {
|
||||
ParseResult<T> __parse(ParseArgs args) {
|
||||
var result = parser._parse(args.increaseDepth());
|
||||
return result.successful
|
||||
? 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 bool failFast;
|
||||
final SyntaxErrorSeverity severity;
|
||||
|
@ -41,7 +41,7 @@ class _Chain<T> extends ListParser<T?> {
|
|||
_Chain(this.parsers, this.failFast, this.severity);
|
||||
|
||||
@override
|
||||
ParseResult<List<T?>?> __parse(ParseArgs args) {
|
||||
ParseResult<List<T>> __parse(ParseArgs args) {
|
||||
var errors = <SyntaxError>[];
|
||||
var results = <T?>[];
|
||||
var spans = <FileSpan>[];
|
||||
|
@ -61,7 +61,10 @@ class _Chain<T> extends ListParser<T?> {
|
|||
successful = false;
|
||||
}
|
||||
|
||||
//TODO: To be looked at
|
||||
//if (result.value != null) {
|
||||
results.add(result.value);
|
||||
//}
|
||||
|
||||
if (result.span != null) {
|
||||
spans.add(result.span!);
|
||||
|
@ -74,14 +77,14 @@ class _Chain<T> extends ListParser<T?> {
|
|||
span = spans.reduce((a, b) => a.expand(b));
|
||||
}
|
||||
|
||||
return ParseResult<List<T?>?>(
|
||||
return ParseResult<List<T>>(
|
||||
args.trampoline,
|
||||
args.scanner,
|
||||
this,
|
||||
successful,
|
||||
errors,
|
||||
span: span,
|
||||
value: List<T?>.unmodifiable(results),
|
||||
value: List<T>.unmodifiable(results),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ class _Check<T> extends Parser<T> {
|
|||
_Check(this.parser, this.matcher, this.errorMessage, this.severity);
|
||||
|
||||
@override
|
||||
ParseResult<T?> __parse(ParseArgs args) {
|
||||
ParseResult<T> __parse(ParseArgs args) {
|
||||
var matchState = {};
|
||||
var result = parser._parse(args.increaseDepth()).change(parser: this);
|
||||
if (!result.successful)
|
||||
|
|
|
@ -7,6 +7,7 @@ import 'package:matcher/matcher.dart';
|
|||
import 'package:source_span/source_span.dart';
|
||||
import 'package:string_scanner/string_scanner.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
import 'package:optional/optional.dart';
|
||||
import '../error.dart';
|
||||
|
||||
part 'any.dart';
|
||||
|
@ -67,9 +68,9 @@ class ParseArgs {
|
|||
|
||||
/// A parser combinator, which can parse very complicated grammars in a manageable manner.
|
||||
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;
|
||||
|
||||
if (args.trampoline.hasMemoized(this, pos))
|
||||
|
@ -86,7 +87,7 @@ abstract class Parser<T> {
|
|||
}
|
||||
|
||||
/// 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);
|
||||
return _parse(args);
|
||||
}
|
||||
|
@ -105,7 +106,7 @@ abstract class Parser<T> {
|
|||
|
||||
// TODO: Type issue
|
||||
/// 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);
|
||||
}
|
||||
|
||||
|
@ -128,7 +129,7 @@ abstract class Parser<T> {
|
|||
}
|
||||
|
||||
/// 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);
|
||||
}
|
||||
|
||||
|
@ -171,7 +172,7 @@ abstract class Parser<T> {
|
|||
Parser<T> or<U>(Parser<T> other) => any<T>([this, other]);
|
||||
|
||||
/// 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.
|
||||
///
|
||||
|
@ -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())
|
||||
.map((r) => r.value ?? defaultValue);
|
||||
|
||||
Parser<T?> surroundedBySquareBrackets({T? defaultValue}) => opt()
|
||||
Parser<T> surroundedBySquareBrackets({required T defaultValue}) => opt()
|
||||
.surroundedBy(match('[').space(), match(']').space())
|
||||
.map((r) => r.value ?? defaultValue);
|
||||
|
||||
|
@ -336,7 +337,9 @@ class Trampoline {
|
|||
}
|
||||
|
||||
bool isActive(Parser parser, int position) {
|
||||
if (!_active.containsKey(parser)) return false;
|
||||
if (!_active.containsKey(parser)) {
|
||||
return false;
|
||||
}
|
||||
var q = _active[parser]!;
|
||||
if (q.isEmpty) return false;
|
||||
//return q.contains(position);
|
||||
|
|
|
@ -7,8 +7,8 @@ class _Compare<T> extends ListParser<T> {
|
|||
_Compare(this.parser, this.compare);
|
||||
|
||||
@override
|
||||
ParseResult<List<T>?> __parse(ParseArgs args) {
|
||||
ParseResult<List<T>?> result = parser._parse(args.increaseDepth());
|
||||
ParseResult<List<T>> __parse(ParseArgs args) {
|
||||
ParseResult<List<T>> result = parser._parse(args.increaseDepth());
|
||||
if (!result.successful) return result;
|
||||
|
||||
result = result.change(
|
||||
|
|
|
@ -7,7 +7,7 @@ class _FoldErrors<T> extends Parser<T> {
|
|||
_FoldErrors(this.parser, this.equal);
|
||||
|
||||
@override
|
||||
ParseResult<T?> __parse(ParseArgs args) {
|
||||
ParseResult<T> __parse(ParseArgs args) {
|
||||
var result = parser._parse(args.increaseDepth()).change(parser: this);
|
||||
var errors = result.errors.fold<List<SyntaxError>>([], (out, e) {
|
||||
if (!out.any((b) => equal(e, b))) out.add(e);
|
||||
|
|
|
@ -16,7 +16,7 @@ class _Longest<T> extends Parser<T> {
|
|||
_Longest(this.parsers, this.errorMessage, this.severity);
|
||||
|
||||
@override
|
||||
ParseResult<T?> _parse(ParseArgs args) {
|
||||
ParseResult<T> _parse(ParseArgs args) {
|
||||
var inactive = parsers
|
||||
.toList()
|
||||
.where((p) => !args.trampoline.isActive(p, args.scanner.position));
|
||||
|
@ -27,7 +27,7 @@ class _Longest<T> extends Parser<T> {
|
|||
|
||||
int replay = args.scanner.position;
|
||||
var errors = <SyntaxError>[];
|
||||
var results = <ParseResult<T?>>[];
|
||||
var results = <ParseResult<T>>[];
|
||||
|
||||
for (var parser in inactive) {
|
||||
var result = parser._parse(args.increaseDepth());
|
||||
|
@ -59,10 +59,10 @@ class _Longest<T> extends Parser<T> {
|
|||
}
|
||||
|
||||
@override
|
||||
ParseResult<T?> __parse(ParseArgs args) {
|
||||
ParseResult<T> __parse(ParseArgs args) {
|
||||
int replay = args.scanner.position;
|
||||
var errors = <SyntaxError>[];
|
||||
var results = <ParseResult<T?>>[];
|
||||
var results = <ParseResult<T>>[];
|
||||
|
||||
for (var parser in parsers) {
|
||||
var result = parser._parse(args.increaseDepth());
|
||||
|
|
|
@ -2,14 +2,14 @@ part of lex.src.combinator;
|
|||
|
||||
class _Map<T, U> extends Parser<U> {
|
||||
final Parser<T> parser;
|
||||
final U Function(ParseResult<T?>) f;
|
||||
final U Function(ParseResult<T>) f;
|
||||
|
||||
_Map(this.parser, this.f);
|
||||
|
||||
@override
|
||||
ParseResult<U?> __parse(ParseArgs args) {
|
||||
ParseResult<U> __parse(ParseArgs args) {
|
||||
var result = parser._parse(args.increaseDepth());
|
||||
return ParseResult<U?>(
|
||||
return ParseResult<U>(
|
||||
args.trampoline,
|
||||
args.scanner,
|
||||
this,
|
||||
|
@ -34,12 +34,12 @@ class _Map<T, U> extends Parser<U> {
|
|||
|
||||
class _Change<T, U> extends Parser<U> {
|
||||
final Parser<T> parser;
|
||||
final ParseResult<U?> Function(ParseResult<T?>) f;
|
||||
final ParseResult<U> Function(ParseResult<T>) f;
|
||||
|
||||
_Change(this.parser, this.f);
|
||||
|
||||
@override
|
||||
ParseResult<U?> __parse(ParseArgs args) {
|
||||
ParseResult<U> __parse(ParseArgs args) {
|
||||
return f(parser._parse(args.increaseDepth())).change(parser: this);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ class _MaxDepth<T> extends Parser<T> {
|
|||
_MaxDepth(this.parser, this.cap);
|
||||
|
||||
@override
|
||||
ParseResult<T?> __parse(ParseArgs args) {
|
||||
ParseResult<T> __parse(ParseArgs args) {
|
||||
if (args.depth > cap) {
|
||||
return ParseResult<T>(args.trampoline, args.scanner, this, false, []);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ class _Negate<T> extends Parser<T> {
|
|||
_Negate(this.parser, this.errorMessage, this.severity);
|
||||
|
||||
@override
|
||||
ParseResult<T?> __parse(ParseArgs args) {
|
||||
ParseResult<T> __parse(ParseArgs args) {
|
||||
var result = parser._parse(args.increaseDepth()).change(parser: this);
|
||||
|
||||
if (!result.successful) {
|
||||
|
|
|
@ -7,7 +7,7 @@ class _Opt<T> extends Parser<T> {
|
|||
_Opt(this.parser, this.backtrack);
|
||||
|
||||
@override
|
||||
ParseResult<T?> __parse(ParseArgs args) {
|
||||
ParseResult<T> __parse(ParseArgs args) {
|
||||
var replay = args.scanner.position;
|
||||
var result = parser._parse(args.increaseDepth());
|
||||
|
||||
|
@ -35,9 +35,9 @@ class _ListOpt<T> extends ListParser<T> {
|
|||
_ListOpt(this.parser, this.backtrack);
|
||||
|
||||
@override
|
||||
ParseResult<List<T>?> __parse(ParseArgs args) {
|
||||
ParseResult<List<T>> __parse(ParseArgs args) {
|
||||
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;
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@ class _Reduce<T> extends Parser<T> {
|
|||
_Reduce(this.parser, this.combine);
|
||||
|
||||
@override
|
||||
ParseResult<T?> __parse(ParseArgs args) {
|
||||
ParseResult<List<T>?> result = parser._parse(args.increaseDepth());
|
||||
ParseResult<T> __parse(ParseArgs args) {
|
||||
ParseResult<List<T>> result = parser._parse(args.increaseDepth());
|
||||
|
||||
if (!result.successful)
|
||||
return ParseResult<T>(
|
||||
|
|
|
@ -15,14 +15,14 @@ class Reference<T> extends Parser<T> {
|
|||
}
|
||||
|
||||
@override
|
||||
ParseResult<T?> __parse(ParseArgs args) {
|
||||
ParseResult<T> __parse(ParseArgs args) {
|
||||
if (_parser == null)
|
||||
throw StateError('There is no parser assigned to this reference.');
|
||||
return _parser!._parse(args);
|
||||
}
|
||||
|
||||
@override
|
||||
ParseResult<T?> _parse(ParseArgs args) {
|
||||
ParseResult<T> _parse(ParseArgs args) {
|
||||
if (_parser == null)
|
||||
throw StateError('There is no parser assigned to this reference.');
|
||||
return _parser!._parse(args);
|
||||
|
|
|
@ -12,12 +12,12 @@ class _Repeat<T> extends ListParser<T> {
|
|||
this.backtrack, this.severity);
|
||||
|
||||
@override
|
||||
ParseResult<List<T>?> __parse(ParseArgs args) {
|
||||
ParseResult<List<T>> __parse(ParseArgs args) {
|
||||
var errors = <SyntaxError>[];
|
||||
var results = <T>[];
|
||||
var spans = <FileSpan>[];
|
||||
int success = 0, replay = args.scanner.position;
|
||||
ParseResult<T?> result;
|
||||
ParseResult<T> result;
|
||||
|
||||
do {
|
||||
result = parser._parse(args.increaseDepth());
|
||||
|
@ -51,7 +51,7 @@ class _Repeat<T> extends ListParser<T> {
|
|||
} else if (success > count && exact) {
|
||||
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(
|
||||
severity,
|
||||
tooMany,
|
||||
|
|
|
@ -10,7 +10,7 @@ class _Safe<T> extends Parser<T> {
|
|||
_Safe(this.parser, this.backtrack, this.errorMessage, this.severity);
|
||||
|
||||
@override
|
||||
ParseResult<T?> __parse(ParseArgs args) {
|
||||
ParseResult<T> __parse(ParseArgs args) {
|
||||
var replay = args.scanner.position;
|
||||
|
||||
try {
|
||||
|
|
|
@ -2,12 +2,12 @@ part of lex.src.combinator;
|
|||
|
||||
class _Value<T> extends Parser<T> {
|
||||
final Parser<T> parser;
|
||||
final T Function(ParseResult<T?>) f;
|
||||
final T Function(ParseResult<T>) f;
|
||||
|
||||
_Value(this.parser, this.f);
|
||||
|
||||
@override
|
||||
ParseResult<T?> __parse(ParseArgs args) {
|
||||
ParseResult<T> __parse(ParseArgs args) {
|
||||
var result = parser._parse(args.increaseDepth()).change(parser: this);
|
||||
return result.successful ? result.change(value: f(result)) : result;
|
||||
}
|
||||
|
|
|
@ -15,5 +15,6 @@ dependencies:
|
|||
source_span: ^1.8.1
|
||||
string_scanner: ^1.1.0
|
||||
tuple: ^2.0.0
|
||||
optional: ^6.0.0-nullsafety.2
|
||||
dev_dependencies:
|
||||
test: ^1.17.3
|
|
@ -11,11 +11,11 @@ main() {
|
|||
var numbers = number.plus();
|
||||
|
||||
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]);
|
||||
});
|
||||
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('not numbers')).value, isNull);
|
||||
});
|
||||
|
|
|
@ -139,7 +139,8 @@ abstract class Driver<
|
|||
pipeline.handlers,
|
||||
resolved.fold<Map<String, dynamic>>(
|
||||
<String, dynamic>{}, (out, r) => out..addAll(r.allParams)),
|
||||
(resolved.isEmpty ? null : resolved.first.parseResult)!,
|
||||
//(resolved.isEmpty ? null : resolved.first.parseResult),
|
||||
resolved.first.parseResult,
|
||||
pipeline,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -22,10 +22,11 @@ dependencies:
|
|||
ref: sdk-2.12.x_nnbd
|
||||
path: packages/model
|
||||
angel_route:
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x_nnbd
|
||||
path: packages/route
|
||||
path: ../route
|
||||
# git:
|
||||
# url: https://github.com/dukefirehawk/angel.git
|
||||
# ref: sdk-2.12.x_nnbd
|
||||
# path: packages/route
|
||||
charcode: ^1.2.0
|
||||
combinator:
|
||||
git:
|
||||
|
|
|
@ -311,7 +311,7 @@ class Router<T> {
|
|||
if (parseResult != null) {
|
||||
if (parseResult.successful && scanner.isDone) {
|
||||
var tailResult = parseResult.value?.tail ?? '';
|
||||
print(tailResult);
|
||||
//print(tailResult);
|
||||
var result = RoutingResult<T>(
|
||||
parseResult: parseResult,
|
||||
params: parseResult.value!.params,
|
||||
|
@ -334,13 +334,13 @@ class Router<T> {
|
|||
|
||||
/// Returns the result of [resolve] with [path] passed as
|
||||
/// both `absolute` and `relative`.
|
||||
Iterable<RoutingResult<T?>> resolveAbsolute(String path,
|
||||
Iterable<RoutingResult<T>> resolveAbsolute(String path,
|
||||
{String method = 'GET', bool strip = true}) =>
|
||||
resolveAll(path, path, method: method, strip: strip);
|
||||
|
||||
/// Finds every possible [Route] that matches the given path,
|
||||
/// 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}) {
|
||||
if (_useCache == true) {
|
||||
return _cache.putIfAbsent('$method$absolute',
|
||||
|
|
|
@ -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<RouteResult?> parseResult;
|
||||
final ParseResult<RouteResult> parseResult;
|
||||
|
||||
/// A nested instance, if a sub-path was matched.
|
||||
final Iterable<RoutingResult<T>> nested;
|
||||
|
@ -47,10 +47,10 @@ class RoutingResult<T> {
|
|||
}
|
||||
|
||||
/// All handlers on this sub-path and its children.
|
||||
List<T?> get allHandlers {
|
||||
final handlers = <T?>[];
|
||||
List<T> get allHandlers {
|
||||
final handlers = <T>[];
|
||||
|
||||
void crawl(RoutingResult<T?> result) {
|
||||
void crawl(RoutingResult<T> result) {
|
||||
handlers.addAll(result.handlers);
|
||||
|
||||
if (result.nested.isNotEmpty == true) {
|
||||
|
|
|
@ -7,11 +7,11 @@ environment:
|
|||
sdk: '>=2.12.0 <3.0.0'
|
||||
dependencies:
|
||||
combinator:
|
||||
# path: ../combinator
|
||||
git:
|
||||
url: https://github.com/dukefirehawk/angel.git
|
||||
ref: sdk-2.12.x_nnbd
|
||||
path: packages/combinator
|
||||
path: ../combinator
|
||||
# git:
|
||||
# url: https://github.com/dukefirehawk/angel.git
|
||||
# ref: sdk-2.12.x_nnbd
|
||||
# path: packages/combinator
|
||||
string_scanner: ^1.0.0
|
||||
dev_dependencies:
|
||||
build_runner: ^1.11.5
|
||||
|
|
Loading…
Reference in a new issue