Just need doc and top-level defs
This commit is contained in:
parent
d517dcf235
commit
fa624e48df
8 changed files with 149 additions and 17 deletions
|
@ -13,7 +13,7 @@ class ArgumentContext extends Node {
|
|||
|
||||
@override
|
||||
SourceSpan get span =>
|
||||
new SourceSpan(NAME.span?.start, valueOrVariable.end, toSource());
|
||||
NAME.span.union(COLON.span).union(valueOrVariable.span);
|
||||
|
||||
@override
|
||||
String toSource() => '${NAME.text}:${valueOrVariable.toSource()}';
|
||||
|
|
|
@ -8,8 +8,9 @@ class DocumentContext extends Node {
|
|||
@override
|
||||
SourceSpan get span {
|
||||
if (definitions.isEmpty) return null;
|
||||
return new SourceSpan(
|
||||
definitions.first.start, definitions.last.end, toSource());
|
||||
return definitions
|
||||
.map<SourceSpan>((d) => d.span)
|
||||
.reduce((a, b) => a.union(b));
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -34,7 +34,22 @@ class Parser {
|
|||
|
||||
Token maybe(TokenType type) => next(type) ? current : null;
|
||||
|
||||
DocumentContext parseDocument() {}
|
||||
DocumentContext parseDocument() {
|
||||
List<DefinitionContext> defs = [];
|
||||
DefinitionContext def = parseDefinition();
|
||||
|
||||
while (def != null) {
|
||||
defs.add(def);
|
||||
def = parseDefinition();
|
||||
}
|
||||
|
||||
return new DocumentContext()..definitions.addAll(defs);
|
||||
}
|
||||
|
||||
DefinitionContext parseDefinition() =>
|
||||
parseOperationDefinition() ?? parseFragmentDefinition();
|
||||
|
||||
OperationDefinitionContext parseOperationDefinition() {}
|
||||
|
||||
FragmentDefinitionContext parseFragmentDefinition() {}
|
||||
|
||||
|
@ -45,14 +60,43 @@ class Parser {
|
|||
var NAME = current;
|
||||
return new FragmentSpreadContext(ELLIPSIS, NAME)
|
||||
..directives.addAll(parseDirectives());
|
||||
} else
|
||||
throw new SyntaxError.fromSourceLocation(
|
||||
'Expected name in fragment spread.', ELLIPSIS.span.end);
|
||||
} else {
|
||||
_index--;
|
||||
return null;
|
||||
}
|
||||
} else
|
||||
return null;
|
||||
}
|
||||
|
||||
InlineFragmentContext parseInlineFragment() {}
|
||||
InlineFragmentContext parseInlineFragment() {
|
||||
if (next(TokenType.ELLIPSIS)) {
|
||||
var ELLIPSIS = current;
|
||||
if (next(TokenType.ON)) {
|
||||
var ON = current;
|
||||
var typeCondition = parseTypeCondition();
|
||||
if (typeCondition != null) {
|
||||
var directives = parseDirectives();
|
||||
var selectionSet = parseSelectionSet();
|
||||
if (selectionSet != null) {
|
||||
return new InlineFragmentContext(
|
||||
ELLIPSIS, ON, typeCondition, selectionSet)
|
||||
..directives.addAll(directives);
|
||||
} else
|
||||
throw new SyntaxError.fromSourceLocation(
|
||||
'Expected selection set in inline fragment.',
|
||||
directives.isEmpty
|
||||
? typeCondition.span.end
|
||||
: directives.last.span.end);
|
||||
} else
|
||||
throw new SyntaxError.fromSourceLocation(
|
||||
'Expected type condition after "on" in inline fragment.',
|
||||
ON.span.end);
|
||||
} else
|
||||
throw new SyntaxError.fromSourceLocation(
|
||||
'Expected "on" after "..." in inline fragment.', ELLIPSIS.span.end);
|
||||
} else
|
||||
return null;
|
||||
}
|
||||
|
||||
SelectionSetContext parseSelectionSet() {
|
||||
if (next(TokenType.LBRACE)) {
|
||||
|
@ -240,8 +284,7 @@ class Parser {
|
|||
return out;
|
||||
else
|
||||
throw new SyntaxError.fromSourceLocation(
|
||||
'Expected ")" in argument list.',
|
||||
out.isEmpty ? LPAREN.span.end : out.last.span.end);
|
||||
'Expected ")" in argument list.', LPAREN.span.end);
|
||||
} else
|
||||
return [];
|
||||
}
|
||||
|
|
|
@ -2,6 +2,9 @@ import 'package:test/test.dart';
|
|||
import 'argument_test.dart' as argument;
|
||||
import 'directive_test.dart' as directive;
|
||||
import 'field_test.dart' as field;
|
||||
import 'fragment_spread_test.dart' as fragment_spread;
|
||||
import 'inline_fragment_test.dart' as inline_fragment;
|
||||
import 'selection_set_test.dart' as selection_set;
|
||||
import 'type_test.dart' as type;
|
||||
import 'value_test.dart' as value;
|
||||
import 'variable_definition_test.dart' as variable_definition;
|
||||
|
@ -11,6 +14,9 @@ main() {
|
|||
group('argument', argument.main);
|
||||
group('directive', directive.main);
|
||||
group('field', field.main);
|
||||
group('fragment spread', fragment_spread.main);
|
||||
group('inline fragment', inline_fragment.main);
|
||||
group('selection set', selection_set.main);
|
||||
group('type', type.main);
|
||||
group('value', value.main);
|
||||
group('variable', variable.main);
|
||||
|
|
|
@ -12,10 +12,12 @@ main() {
|
|||
test('exception', () {
|
||||
expect(() => parseArgument('foo'), throwsSyntaxError);
|
||||
expect(() => parseArgument('foo:'), throwsSyntaxError);
|
||||
expect(() => parseArgumentList(r'(foo: $bar'), throwsSyntaxError);
|
||||
});
|
||||
}
|
||||
|
||||
ArgumentContext parseArgument(String text) => parse(text).parseArgument();
|
||||
List<ArgumentContext> parseArgumentList(String text) => parse(text).parseArguments();
|
||||
|
||||
Matcher isArgument(String name, value) => new _IsArgument(name, value);
|
||||
|
||||
|
|
|
@ -19,10 +19,6 @@ main() {
|
|||
isDirective('quux', argument: isArgument('one', 1))
|
||||
])));
|
||||
});
|
||||
|
||||
test('exceptions', () {
|
||||
expect(() => parseFragmentSpread('...'), throwsSyntaxError);
|
||||
});
|
||||
}
|
||||
|
||||
FragmentSpreadContext parseFragmentSpread(String text) =>
|
||||
|
|
71
test/inline_fragment_test.dart
Normal file
71
test/inline_fragment_test.dart
Normal file
|
@ -0,0 +1,71 @@
|
|||
import 'package:graphql_parser/graphql_parser.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'common.dart';
|
||||
import 'argument_test.dart';
|
||||
import 'directive_test.dart';
|
||||
import 'field_test.dart';
|
||||
import 'fragment_spread_test.dart';
|
||||
import 'selection_set_test.dart';
|
||||
|
||||
main() {
|
||||
test('no directives', () {
|
||||
expect(
|
||||
'... on foo {bar, baz: quux}',
|
||||
isInlineFragment('foo',
|
||||
selectionSet: isSelectionSet([
|
||||
isField(fieldName: isFieldName('bar')),
|
||||
isField(fieldName: isFieldName('baz', alias: 'quux'))
|
||||
])));
|
||||
});
|
||||
|
||||
test('with directives', () {
|
||||
expect(
|
||||
'... on foo @bar @baz: 2 @quux(one: 1) {... bar}',
|
||||
isInlineFragment('foo',
|
||||
directives: isDirectiveList([
|
||||
isDirective('bar'),
|
||||
isDirective('baz', valueOrVariable: equals(2)),
|
||||
isDirective('quux', argument: isArgument('one', 1))
|
||||
]),
|
||||
selectionSet: isSelectionSet([isFragmentSpread('bar')])));
|
||||
});
|
||||
|
||||
test('exceptions', () {
|
||||
expect(() => parseInlineFragment('... on foo'), throwsSyntaxError);
|
||||
expect(() => parseInlineFragment('... on foo @bar'), throwsSyntaxError);
|
||||
expect(() => parseInlineFragment('... on'), throwsSyntaxError);
|
||||
expect(() => parseInlineFragment('...'), throwsSyntaxError);
|
||||
});
|
||||
}
|
||||
|
||||
InlineFragmentContext parseInlineFragment(String text) =>
|
||||
parse(text).parseInlineFragment();
|
||||
|
||||
Matcher isInlineFragment(String name,
|
||||
{Matcher directives, Matcher selectionSet}) =>
|
||||
new _IsInlineFragment(name, directives, selectionSet);
|
||||
|
||||
class _IsInlineFragment extends Matcher {
|
||||
final String name;
|
||||
final Matcher directives, selectionSet;
|
||||
|
||||
_IsInlineFragment(this.name, this.directives, this.selectionSet);
|
||||
|
||||
@override
|
||||
Description describe(Description description) {
|
||||
return description.add('is an inline fragment named "$name"');
|
||||
}
|
||||
|
||||
@override
|
||||
bool matches(item, Map matchState) {
|
||||
var fragment =
|
||||
item is InlineFragmentContext ? item : parseInlineFragment(item);
|
||||
if (fragment == null) return false;
|
||||
if (fragment.typeCondition.typeName.name != name) return false;
|
||||
if (directives != null &&
|
||||
!directives.matches(fragment.directives, matchState)) return false;
|
||||
if (selectionSet != null &&
|
||||
!selectionSet.matches(fragment.selectionSet, matchState)) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -3,8 +3,8 @@ import 'package:test/test.dart';
|
|||
import 'common.dart';
|
||||
import 'field_test.dart';
|
||||
import 'fragment_spread_test.dart';
|
||||
import 'inline_fragment_test.dart';
|
||||
|
||||
// TODO: Test inline fragment...
|
||||
main() {
|
||||
test('empty', () {
|
||||
expect('{}', isSelectionSet([]));
|
||||
|
@ -21,11 +21,24 @@ main() {
|
|||
|
||||
test('no commas', () {
|
||||
expect(
|
||||
'{foo bar: baz ...quux}',
|
||||
'''
|
||||
{
|
||||
foo
|
||||
bar: baz ...quux
|
||||
... on foo {bar, baz}
|
||||
}'''
|
||||
.split('\n')
|
||||
.map((s) => s.trim())
|
||||
.join(' '),
|
||||
isSelectionSet([
|
||||
isField(fieldName: isFieldName('foo')),
|
||||
isField(fieldName: isFieldName('bar', alias: 'baz')),
|
||||
isFragmentSpread('quux')
|
||||
isFragmentSpread('quux'),
|
||||
isInlineFragment('foo',
|
||||
selectionSet: isSelectionSet([
|
||||
isField(fieldName: isFieldName('bar')),
|
||||
isField(fieldName: isFieldName('baz')),
|
||||
]))
|
||||
]));
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue