diff --git a/.idea/runConfigurations/tests_in_query_test_dart.xml b/.idea/runConfigurations/tests_in_query_test_dart.xml
new file mode 100644
index 00000000..9ab72dfa
--- /dev/null
+++ b/.idea/runConfigurations/tests_in_query_test_dart.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/graphql_parser/lib/src/language/ast/operation_definition.dart b/graphql_parser/lib/src/language/ast/operation_definition.dart
index 3246e173..e6abaf53 100644
--- a/graphql_parser/lib/src/language/ast/operation_definition.dart
+++ b/graphql_parser/lib/src/language/ast/operation_definition.dart
@@ -1,7 +1,8 @@
+import 'package:source_span/source_span.dart';
+
import '../token.dart';
import 'definition.dart';
import 'directive.dart';
-import 'package:source_span/source_span.dart';
import 'selection_set.dart';
import 'variable_definitions.dart';
@@ -12,7 +13,8 @@ class OperationDefinitionContext extends DefinitionContext {
final SelectionSetContext selectionSet;
bool get isMutation => TYPE?.text == 'mutation';
- bool get isQuery => TYPE?.text == 'query';
+
+ bool get isQuery => TYPE?.text == 'query' || TYPE == null;
String get name => NAME?.text;
diff --git a/graphql_parser/lib/src/language/ast/string_value.dart b/graphql_parser/lib/src/language/ast/string_value.dart
index db96fe05..a5c54b62 100644
--- a/graphql_parser/lib/src/language/ast/string_value.dart
+++ b/graphql_parser/lib/src/language/ast/string_value.dart
@@ -55,8 +55,8 @@ class StringValueContext extends ValueContext {
buf.writeCharCode(next);
}
} else
- throw new SyntaxError.fromSourceLocation(
- 'Unexpected "\\" in string literal.', span.start);
+ throw new SyntaxError(
+ 'Unexpected "\\" in string literal.', span);
} else {
buf.writeCharCode(ch);
}
diff --git a/graphql_parser/lib/src/language/lexer.dart b/graphql_parser/lib/src/language/lexer.dart
index 02309395..87000efd 100644
--- a/graphql_parser/lib/src/language/lexer.dart
+++ b/graphql_parser/lib/src/language/lexer.dart
@@ -35,9 +35,9 @@ final Map _patterns = {
_name: TokenType.NAME
};
-List scan(String text) {
+List scan(String text, {sourceUrl}) {
List out = [];
- var scanner = new SpanScanner(text);
+ var scanner = new SpanScanner(text, sourceUrl: sourceUrl);
while (!scanner.isDone) {
List potential = [];
@@ -54,7 +54,7 @@ List scan(String text) {
if (potential.isEmpty) {
var ch = new String.fromCharCode(scanner.readChar());
throw new SyntaxError(
- "Unexpected token '$ch'.", scanner.state.line, scanner.state.column);
+ "Unexpected token '$ch'.", scanner.emptySpan);
} else {
// Choose longest token
potential.sort((a, b) => b.text.length.compareTo(a.text.length));
diff --git a/graphql_parser/lib/src/language/parser.dart b/graphql_parser/lib/src/language/parser.dart
index b7ec8a55..45f4e780 100644
--- a/graphql_parser/lib/src/language/parser.dart
+++ b/graphql_parser/lib/src/language/parser.dart
@@ -66,13 +66,13 @@ class Parser {
TYPE, NAME, variables, selectionSet)
..directives.addAll(dirs);
else
- throw new SyntaxError.fromSourceLocation(
+ throw new SyntaxError(
'Expected selection set in fragment definition.',
- NAME.span.end);
+ NAME.span);
} else
- throw new SyntaxError.fromSourceLocation(
+ throw new SyntaxError(
'Expected name after operation type "${TYPE.text}" in operation definition.',
- TYPE.span.end);
+ TYPE.span);
} else
return null;
}
@@ -94,21 +94,21 @@ class Parser {
FRAGMENT, NAME, ON, typeCondition, selectionSet)
..directives.addAll(dirs);
else
- throw new SyntaxError.fromSourceLocation(
+ throw new SyntaxError(
'Expected selection set in fragment definition.',
- typeCondition.span.end);
+ typeCondition.span);
} else
- throw new SyntaxError.fromSourceLocation(
+ throw new SyntaxError(
'Expected type condition after "on" in fragment definition.',
- ON.span.end);
+ ON.span);
} else
- throw new SyntaxError.fromSourceLocation(
+ throw new SyntaxError(
'Expected "on" after name "${NAME.text}" in fragment definition.',
- NAME.span.end);
+ NAME.span);
} else
- throw new SyntaxError.fromSourceLocation(
+ throw new SyntaxError(
'Expected name after "fragment" in fragment definition.',
- FRAGMENT.span.end);
+ FRAGMENT.span);
} else
return null;
}
@@ -142,18 +142,18 @@ class Parser {
ELLIPSIS, ON, typeCondition, selectionSet)
..directives.addAll(directives);
} else
- throw new SyntaxError.fromSourceLocation(
+ throw new SyntaxError(
'Expected selection set in inline fragment.',
directives.isEmpty
- ? typeCondition.span.end
- : directives.last.span.end);
+ ? typeCondition.span
+ : directives.last.span);
} else
- throw new SyntaxError.fromSourceLocation(
+ throw new SyntaxError(
'Expected type condition after "on" in inline fragment.',
- ON.span.end);
+ ON.span);
} else
- throw new SyntaxError.fromSourceLocation(
- 'Expected "on" after "..." in inline fragment.', ELLIPSIS.span.end);
+ throw new SyntaxError(
+ 'Expected "on" after "..." in inline fragment.', ELLIPSIS.span);
} else
return null;
}
@@ -174,9 +174,9 @@ class Parser {
return new SelectionSetContext(LBRACE, current)
..selections.addAll(selections);
else
- throw new SyntaxError.fromSourceLocation(
+ throw new SyntaxError(
'Expected "}" after selection set.',
- selections.isEmpty ? LBRACE.span.end : selections.last.span.end);
+ selections.isEmpty ? LBRACE.span : selections.last.span);
} else
return null;
}
@@ -216,8 +216,8 @@ class Parser {
return new FieldNameContext(
null, new AliasContext(NAME1, COLON, current));
else
- throw new SyntaxError.fromSourceLocation(
- 'Expected name after colon in alias.', COLON.span.end);
+ throw new SyntaxError(
+ 'Expected name after colon in alias.', COLON.span);
} else
return new FieldNameContext(NAME1);
} else
@@ -240,8 +240,8 @@ class Parser {
return new VariableDefinitionsContext(LPAREN, current)
..variableDefinitions.addAll(defs);
else
- throw new SyntaxError.fromSourceLocation(
- 'Expected ")" after variable definitions.', LPAREN.span.end);
+ throw new SyntaxError(
+ 'Expected ")" after variable definitions.', LPAREN.span);
} else
return null;
}
@@ -257,11 +257,11 @@ class Parser {
return new VariableDefinitionContext(
variable, COLON, type, defaultValue);
} else
- throw new SyntaxError.fromSourceLocation(
- 'Expected type in variable definition.', COLON.span.end);
+ throw new SyntaxError(
+ 'Expected type in variable definition.', COLON.span);
} else
- throw new SyntaxError.fromSourceLocation(
- 'Expected ":" in variable definition.', variable.span.end);
+ throw new SyntaxError(
+ 'Expected ":" in variable definition.', variable.span);
} else
return null;
}
@@ -287,11 +287,11 @@ class Parser {
if (next(TokenType.RBRACKET)) {
return new ListTypeContext(LBRACKET, type, current);
} else
- throw new SyntaxError.fromSourceLocation(
- 'Expected "]" in list type.', type.span.end);
+ throw new SyntaxError(
+ 'Expected "]" in list type.', type.span);
} else
- throw new SyntaxError.fromSourceLocation(
- 'Expected type after "[".', LBRACKET.span.end);
+ throw new SyntaxError(
+ 'Expected type after "[".', LBRACKET.span);
} else
return null;
}
@@ -320,9 +320,9 @@ class Parser {
return new DirectiveContext(
ARROBA, NAME, COLON, null, null, null, val);
else
- throw new SyntaxError.fromSourceLocation(
+ throw new SyntaxError(
'Expected value or variable in directive after colon.',
- COLON.span.end);
+ COLON.span);
} else if (next(TokenType.LPAREN)) {
var LPAREN = current;
var arg = parseArgument();
@@ -331,17 +331,17 @@ class Parser {
return new DirectiveContext(
ARROBA, NAME, null, LPAREN, current, arg, null);
} else
- throw new SyntaxError.fromSourceLocation(
- 'Expected \')\'', arg.valueOrVariable.span.end);
+ throw new SyntaxError(
+ 'Expected \')\'', arg.valueOrVariable.span);
} else
- throw new SyntaxError.fromSourceLocation(
- 'Expected argument in directive.', LPAREN.span.end);
+ throw new SyntaxError(
+ 'Expected argument in directive.', LPAREN.span);
} else
return new DirectiveContext(
ARROBA, NAME, null, null, null, null, null);
} else
- throw new SyntaxError.fromSourceLocation(
- 'Expected name for directive.', ARROBA.span.end);
+ throw new SyntaxError(
+ 'Expected name for directive.', ARROBA.span);
} else
return null;
}
@@ -363,8 +363,8 @@ class Parser {
if (next(TokenType.RPAREN))
return out;
else
- throw new SyntaxError.fromSourceLocation(
- 'Expected ")" in argument list.', LPAREN.span.end);
+ throw new SyntaxError(
+ 'Expected ")" in argument list.', LPAREN.span);
} else
return [];
}
@@ -378,11 +378,11 @@ class Parser {
if (val != null)
return new ArgumentContext(NAME, COLON, val);
else
- throw new SyntaxError.fromSourceLocation(
- 'Expected value or variable in argument.', COLON.span.end);
+ throw new SyntaxError(
+ 'Expected value or variable in argument.', COLON.span);
} else
- throw new SyntaxError.fromSourceLocation(
- 'Expected colon after name in argument.', NAME.span.end);
+ throw new SyntaxError(
+ 'Expected colon after name in argument.', NAME.span);
} else
return null;
}
@@ -406,9 +406,9 @@ class Parser {
if (next(TokenType.NAME))
return new VariableContext(DOLLAR, current);
else
- throw new SyntaxError.fromSourceLocation(
+ throw new SyntaxError(
'Expected name for variable; found a lone "\$" instead.',
- DOLLAR.span.end);
+ DOLLAR.span);
} else
return null;
}
@@ -420,8 +420,8 @@ class Parser {
if (value != null) {
return new DefaultValueContext(EQUALS, value);
} else
- throw new SyntaxError.fromSourceLocation(
- 'Expected value after "=" sign.', EQUALS.span.end);
+ throw new SyntaxError(
+ 'Expected value after "=" sign.', EQUALS.span);
} else
return null;
}
@@ -474,8 +474,8 @@ class Parser {
if (next(TokenType.RBRACKET)) {
return new ArrayValueContext(LBRACKET, current)..values.addAll(values);
} else
- throw new SyntaxError.fromSourceLocation(
- 'Unterminated array literal.', LBRACKET.span.end);
+ throw new SyntaxError(
+ 'Unterminated array literal.', LBRACKET.span);
} else
return null;
}
diff --git a/graphql_parser/lib/src/language/syntax_error.dart b/graphql_parser/lib/src/language/syntax_error.dart
index 0929a27b..c06a8659 100644
--- a/graphql_parser/lib/src/language/syntax_error.dart
+++ b/graphql_parser/lib/src/language/syntax_error.dart
@@ -1,18 +1,11 @@
import 'package:source_span/source_span.dart';
-import 'token.dart';
class SyntaxError implements Exception {
final String message;
- final int line, column;
- final Token offendingToken;
+ final FileSpan span;
- SyntaxError(this.message, this.line, this.column, [this.offendingToken]);
-
- factory SyntaxError.fromSourceLocation(
- String message, SourceLocation location,
- [Token offendingToken]) =>
- new SyntaxError(message, location.line, location.column, offendingToken);
+ SyntaxError(this.message, this.span);
@override
- String toString() => 'Syntax error at line $line, column $column: $message';
+ String toString() => 'Syntax error at ${span.start.toolString}: $message\n${span.highlight()}';
}
diff --git a/graphql_schema/example/todo.dart b/graphql_schema/example/todo.dart
index 5561c806..b837d612 100644
--- a/graphql_schema/example/todo.dart
+++ b/graphql_schema/example/todo.dart
@@ -4,9 +4,14 @@ final GraphQLSchema todoSchema = new GraphQLSchema(
query: objectType('Todo', [
field(
'text',
- innerType: graphQLString.nonNullable(),
+ type: graphQLString.nonNullable(),
+ resolve: resolveToNull,
+ ),
+ field(
+ 'created_at',
+ type: graphQLDate,
+ resolve: resolveToNull,
),
- field('created_at', innerType: graphQLDate),
]),
);
@@ -14,7 +19,11 @@ main() {
// Validation
var validation = todoSchema.query.validate(
'@root',
- {'foo': 'bar', 'text': null, 'created_at': 24,},
+ {
+ 'foo': 'bar',
+ 'text': null,
+ 'created_at': 24,
+ },
);
if (validation.successful) {
diff --git a/graphql_schema/lib/src/field.dart b/graphql_schema/lib/src/field.dart
index d50c3827..f369f299 100644
--- a/graphql_schema/lib/src/field.dart
+++ b/graphql_schema/lib/src/field.dart
@@ -11,7 +11,7 @@ class GraphQLField {
GraphQLField(this.name,
{Iterable arguments: const [],
- this.resolve,
+ @required this.resolve,
this.type}) {
this.arguments.addAll(arguments ?? []);
}
diff --git a/graphql_schema/lib/src/gen.dart b/graphql_schema/lib/src/gen.dart
index e34575ca..5b833bf2 100644
--- a/graphql_schema/lib/src/gen.dart
+++ b/graphql_schema/lib/src/gen.dart
@@ -5,10 +5,9 @@ GraphQLObjectType objectType(String name,
new GraphQLObjectType(name)..fields.addAll(fields ?? []);
GraphQLField field(String name,
- {Iterable> arguments:
- const >[],
+ {Iterable> arguments: const [],
GraphQLFieldResolver resolve,
- GraphQLType innerType}) {
+ GraphQLType type}) {
return new GraphQLField(name,
- arguments: arguments, resolve: resolve, type: innerType);
+ arguments: arguments, resolve: resolve, type: type);
}
diff --git a/graphql_schema/lib/src/schema.dart b/graphql_schema/lib/src/schema.dart
index 35c8c450..cfbb90d2 100644
--- a/graphql_schema/lib/src/schema.dart
+++ b/graphql_schema/lib/src/schema.dart
@@ -20,3 +20,6 @@ class GraphQLSchema {
GraphQLSchema graphQLSchema(
{@required GraphQLObjectType query, GraphQLObjectType mutation}) =>
new GraphQLSchema(query: query, mutation: mutation);
+
+/// A default resolver that always returns `null`.
+resolveToNull(_, __) => null;
diff --git a/graphql_schema/pubspec.yaml b/graphql_schema/pubspec.yaml
index 7ea8d836..d13510f7 100644
--- a/graphql_schema/pubspec.yaml
+++ b/graphql_schema/pubspec.yaml
@@ -5,5 +5,7 @@ author: Tobe O
homepage: https://github.com/thosakwe/graphql_schema
environment:
sdk: ">=1.8.0 <3.0.0"
+dependencies:
+ meta: ^1.0.0
dev_dependencies:
test: ^0.12.0
\ No newline at end of file
diff --git a/graphql_schema/test/common.dart b/graphql_schema/test/common.dart
index f0147bc2..5b5ae5d2 100644
--- a/graphql_schema/test/common.dart
+++ b/graphql_schema/test/common.dart
@@ -1,14 +1,14 @@
import 'package:graphql_schema/graphql_schema.dart';
final GraphQLObjectType pokemonType = objectType('Pokemon', [
- field('species', innerType: graphQLString),
- field('catch_date', innerType: graphQLDate)
+ field('species', type: graphQLString),
+ field('catch_date', type: graphQLDate)
]);
final GraphQLObjectType trainerType =
- objectType('Trainer', [field('name', innerType: graphQLString)]);
+ objectType('Trainer', [field('name', type: graphQLString)]);
final GraphQLObjectType pokemonRegionType = objectType('PokemonRegion', [
- field('trainer', innerType: trainerType),
- field('pokemon_species', innerType: listType(pokemonType))
+ field('trainer', type: trainerType),
+ field('pokemon_species', type: listType(pokemonType))
]);
diff --git a/graphql_server/lib/graphql.dart b/graphql_server/lib/graphql_server.dart
similarity index 89%
rename from graphql_server/lib/graphql.dart
rename to graphql_server/lib/graphql_server.dart
index dd5d5cfe..a22fb8b5 100644
--- a/graphql_server/lib/graphql.dart
+++ b/graphql_server/lib/graphql_server.dart
@@ -44,9 +44,25 @@ class GraphQL {
}
}
+ Future