Just need doc and top-level defs

This commit is contained in:
thosakwe 2017-07-04 13:32:52 -04:00
parent d517dcf235
commit fa624e48df
8 changed files with 149 additions and 17 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -19,10 +19,6 @@ main() {
isDirective('quux', argument: isArgument('one', 1))
])));
});
test('exceptions', () {
expect(() => parseFragmentSpread('...'), throwsSyntaxError);
});
}
FragmentSpreadContext parseFragmentSpread(String text) =>

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

View file

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