Fixed disjoint spans

This commit is contained in:
thosakwe 2017-07-05 18:44:13 -04:00
parent a059010428
commit cfb509abea
30 changed files with 95 additions and 90 deletions

View file

@ -1,6 +1,6 @@
import '../token.dart';
import 'node.dart';
import 'package:source_span/src/span.dart';
import 'package:source_span/source_span.dart';
class AliasContext extends Node {
final Token NAME1, COLON, NAME2;
@ -14,7 +14,7 @@ class AliasContext extends Node {
String get name => NAME2.text;
@override
SourceSpan get span => NAME1.span.union(COLON.span).union(NAME2.span);
FileSpan get span => NAME1.span.expand(COLON.span).expand(NAME2.span);
@override
String toSource() => '${NAME1.text}:${NAME2.text}';

View file

@ -1,6 +1,6 @@
import 'package:source_span/source_span.dart';
import '../token.dart';
import 'node.dart';
import 'package:source_span/src/span.dart';
import 'value_or_variable.dart';
class ArgumentContext extends Node {
@ -12,8 +12,8 @@ class ArgumentContext extends Node {
String get name => NAME.text;
@override
SourceSpan get span =>
NAME.span.union(COLON.span).union(valueOrVariable.span);
FileSpan get span =>
NAME.span.expand(COLON.span).expand(valueOrVariable.span);
@override
String toSource() => '${NAME.text}:${valueOrVariable.toSource()}';

View file

@ -1,5 +1,5 @@
import 'package:source_span/source_span.dart';
import '../token.dart';
import 'package:source_span/src/span.dart';
import 'value.dart';
class ArrayValueContext extends ValueContext {
@ -9,8 +9,10 @@ class ArrayValueContext extends ValueContext {
ArrayValueContext(this.LBRACKET, this.RBRACKET);
@override
SourceSpan get span =>
new SourceSpan(LBRACKET.span?.end, RBRACKET.span?.end, toSource());
FileSpan get span {
var out = values.fold<FileSpan>(LBRACKET.span, (o, v) => o.expand(v.span));
return out.expand(RBRACKET.span);
}
@override
List get value => values.map((v) => v.value).toList();

View file

@ -1,5 +1,5 @@
import '../token.dart';
import 'package:source_span/src/span.dart';
import 'package:source_span/source_span.dart';
import 'value.dart';
class BooleanValueContext extends ValueContext {
@ -16,7 +16,7 @@ class BooleanValueContext extends ValueContext {
get value => booleanValue;
@override
SourceSpan get span => BOOLEAN.span;
FileSpan get span => BOOLEAN.span;
@override
String toSource() => BOOLEAN.text;

View file

@ -1,6 +1,6 @@
import '../token.dart';
import 'node.dart';
import 'package:source_span/src/span.dart';
import 'package:source_span/source_span.dart';
import 'value.dart';
class DefaultValueContext extends Node {
@ -10,8 +10,7 @@ class DefaultValueContext extends Node {
DefaultValueContext(this.EQUALS, this.value);
@override
SourceSpan get span =>
new SourceSpan(EQUALS.span?.start, value.end, toSource());
FileSpan get span => EQUALS.span.expand(value.span);
@override
String toSource() => '=${value.toSource()}';

View file

@ -15,14 +15,16 @@ class DirectiveContext extends Node {
}
@override
SourceSpan get span {
SourceLocation end = NAME.span?.end;
FileSpan get span {
var out = ARROBA.span.expand(NAME.span);
if (valueOrVariable != null)
end = valueOrVariable.end;
else if (RPAREN != null) end = RPAREN.span?.end;
if (COLON != null) {
out = out.expand(COLON.span).expand(valueOrVariable.span);
} else if (LPAREN != null) {
out = out.expand(LPAREN.span).expand(argument.span).expand(RPAREN.span);
}
return new SourceSpan(ARROBA.span?.start, end, toSource());
return out;
}
@override

View file

@ -1,16 +1,16 @@
import 'package:source_span/source_span.dart';
import 'definition.dart';
import 'node.dart';
import 'package:source_span/src/span.dart';
class DocumentContext extends Node {
final List<DefinitionContext> definitions = [];
@override
SourceSpan get span {
FileSpan get span {
if (definitions.isEmpty) return null;
return definitions
.map<SourceSpan>((d) => d.span)
.reduce((a, b) => a.union(b));
.map<FileSpan>((d) => d.span)
.reduce((a, b) => a.expand(b));
}
@override

View file

@ -1,8 +1,8 @@
import 'package:source_span/source_span.dart';
import 'argument.dart';
import 'directive.dart';
import 'field_name.dart';
import 'node.dart';
import 'package:source_span/source_span.dart';
import 'selection_set.dart';
class FieldContext extends Node {
@ -14,15 +14,15 @@ class FieldContext extends Node {
FieldContext(this.fieldName, [this.selectionSet]);
@override
SourceSpan get span {
FileSpan get span {
if (selectionSet != null)
return fieldName.span.union(selectionSet.span);
return fieldName.span.expand(selectionSet.span);
else if (directives.isNotEmpty)
return directives.fold<SourceSpan>(
fieldName.span, (out, d) => out.union(d.span));
return directives.fold<FileSpan>(
fieldName.span, (out, d) => out.expand(d.span));
if (arguments.isNotEmpty)
return arguments.fold<SourceSpan>(
fieldName.span, (out, a) => out.union(a.span));
return arguments.fold<FileSpan>(
fieldName.span, (out, a) => out.expand(a.span));
else
return fieldName.span;
}

View file

@ -1,7 +1,7 @@
import 'package:source_span/source_span.dart';
import '../token.dart';
import 'alias.dart';
import 'node.dart';
import 'package:source_span/src/span.dart';
class FieldNameContext extends Node {
final Token NAME;
@ -14,7 +14,7 @@ class FieldNameContext extends Node {
String get name => NAME?.text;
@override
SourceSpan get span => alias?.span ?? NAME.span;
FileSpan get span => alias?.span ?? NAME.span;
@override
String toSource() => alias?.toSource() ?? NAME.text;

View file

@ -1,7 +1,7 @@
import '../token.dart';
import 'definition.dart';
import 'directive.dart';
import 'package:source_span/src/span.dart';
import 'package:source_span/source_span.dart';
import 'selection_set.dart';
import 'type_condition.dart';
@ -17,8 +17,14 @@ class FragmentDefinitionContext extends DefinitionContext {
this.FRAGMENT, this.NAME, this.ON, this.typeCondition, this.selectionSet);
@override
SourceSpan get span =>
new SourceSpan(FRAGMENT.span?.start, selectionSet.end, toSource());
FileSpan get span {
var out = FRAGMENT.span
.expand(NAME.span)
.expand(ON.span)
.expand(typeCondition.span);
out = directives.fold<FileSpan>(out, (o, d) => o.expand(d.span));
return out.expand(selectionSet.span);
}
@override
String toSource() =>

View file

@ -12,10 +12,10 @@ class FragmentSpreadContext extends Node {
String get name => NAME.text;
@override
SourceSpan get span {
var out = ELLIPSIS.span.union(NAME.span);
FileSpan get span {
var out = ELLIPSIS.span.expand(NAME.span);
if (directives.isEmpty) return out;
return directives.fold<SourceSpan>(out, (o, d) => o.union(d.span));
return directives.fold<FileSpan>(out, (o, d) => o.expand(d.span));
}
@override

View file

@ -1,7 +1,7 @@
import '../token.dart';
import 'directive.dart';
import 'node.dart';
import 'package:source_span/src/span.dart';
import 'package:source_span/source_span.dart';
import 'selection_set.dart';
import 'type_condition.dart';
@ -15,8 +15,11 @@ class InlineFragmentContext extends Node {
this.ELLIPSIS, this.ON, this.typeCondition, this.selectionSet);
@override
SourceSpan get span =>
new SourceSpan(ELLIPSIS.span?.start, selectionSet.end, toSource());
FileSpan get span {
var out = ELLIPSIS.span.expand(ON.span).expand(typeCondition.span);
out = directives.fold<FileSpan>(out, (o, d) => o.expand(d.span));
return out.expand(selectionSet.span);
}
@override
String toSource() =>

View file

@ -1,6 +1,6 @@
import '../token.dart';
import 'node.dart';
import 'package:source_span/src/span.dart';
import 'package:source_span/source_span.dart';
import 'type.dart';
class ListTypeContext extends Node {
@ -10,8 +10,7 @@ class ListTypeContext extends Node {
ListTypeContext(this.LBRACKET, this.type, this.RBRACKET);
@override
SourceSpan get span =>
new SourceSpan(LBRACKET.span?.end, RBRACKET.span?.end, toSource());
FileSpan get span => LBRACKET.span.expand(type.span).expand(RBRACKET.span);
@override
String toSource() => '[${type.toSource()}]';

View file

@ -1,7 +1,7 @@
import 'package:source_span/source_span.dart';
abstract class Node {
SourceSpan get span;
FileSpan get span;
SourceLocation get start => span.start;
SourceLocation get end => span.end;

View file

@ -24,7 +24,7 @@ class NumberValueContext extends ValueContext {
get value => numberValue;
@override
SourceSpan get span => NUMBER.span;
FileSpan get span => NUMBER.span;
@override
String toSource() => NUMBER.text;

View file

@ -1,7 +1,7 @@
import '../token.dart';
import 'definition.dart';
import 'directive.dart';
import 'package:source_span/src/span.dart';
import 'package:source_span/source_span.dart';
import 'selection_set.dart';
import 'variable_definitions.dart';
@ -22,9 +22,11 @@ class OperationDefinitionContext extends DefinitionContext {
}
@override
SourceSpan get span {
FileSpan get span {
if (TYPE == null) return selectionSet.span;
return new SourceSpan(TYPE.span?.start, selectionSet.end, toSource());
var out = TYPE.span.expand(NAME.span);
out = directives.fold<FileSpan>(out, (o, d) => o.expand(d.span));
return out.expand(selectionSet.span);
}
@override

View file

@ -2,7 +2,7 @@ import 'field.dart';
import 'fragment_spread.dart';
import 'inline_fragment.dart';
import 'node.dart';
import 'package:source_span/src/span.dart';
import 'package:source_span/source_span.dart';
class SelectionContext extends Node {
final FieldContext field;
@ -14,7 +14,7 @@ class SelectionContext extends Node {
}
@override
SourceSpan get span =>
FileSpan get span =>
field?.span ?? fragmentSpread?.span ?? inlineFragment?.span;
@override

View file

@ -1,6 +1,6 @@
import 'package:source_span/source_span.dart';
import '../token.dart';
import 'node.dart';
import 'package:source_span/src/span.dart';
import 'selection.dart';
class SelectionSetContext extends Node {
@ -10,10 +10,10 @@ class SelectionSetContext extends Node {
SelectionSetContext(this.LBRACE, this.RBRACE);
@override
SourceSpan get span {
FileSpan get span {
var out =
selections.fold<SourceSpan>(LBRACE.span, (out, s) => out.union(s.span));
return out.union(RBRACE.span);
selections.fold<FileSpan>(LBRACE.span, (out, s) => out.expand(s.span));
return out.expand(RBRACE.span);
}
@override

View file

@ -1,4 +1,3 @@
import 'dart:convert';
import 'package:charcode/charcode.dart';
import 'package:source_span/source_span.dart';
import '../syntax_error.dart';
@ -11,7 +10,7 @@ class StringValueContext extends ValueContext {
StringValueContext(this.STRING);
@override
SourceSpan get span => STRING.span;
FileSpan get span => STRING.span;
String get stringValue {
var text = STRING.text.substring(1, STRING.text.length - 1);

View file

@ -16,20 +16,9 @@ class TypeContext extends Node {
}
@override
SourceSpan get span {
SourceLocation start, end;
if (typeName != null) {
start = typeName.start;
end = typeName.end;
} else if (listType != null) {
start = listType.start;
end = listType.end;
}
if (EXCLAMATION != null) end = EXCLAMATION.span?.end;
return new SourceSpan(start, end, toSource());
FileSpan get span {
var out = typeName?.span ?? listType.span;
return EXCLAMATION != null ? out.expand(EXCLAMATION.span) : out;
}
@override

View file

@ -1,5 +1,5 @@
import 'node.dart';
import 'package:source_span/src/span.dart';
import 'package:source_span/source_span.dart';
import 'type_name.dart';
class TypeConditionContext extends Node {
@ -8,7 +8,7 @@ class TypeConditionContext extends Node {
TypeConditionContext(this.typeName);
@override
SourceSpan get span => typeName.span;
FileSpan get span => typeName.span;
@override
String toSource() => typeName.toSource();

View file

@ -1,5 +1,5 @@
import 'node.dart';
import 'package:source_span/src/span.dart';
import 'package:source_span/source_span.dart';
import '../token.dart';
class TypeNameContext extends Node {
@ -8,7 +8,7 @@ class TypeNameContext extends Node {
String get name => NAME.text;
@override
SourceSpan get span => NAME.span;
FileSpan get span => NAME.span;
TypeNameContext(this.NAME);

View file

@ -1,5 +1,5 @@
import 'node.dart';
import 'package:source_span/src/span.dart';
import 'package:source_span/source_span.dart';
import 'value.dart';
import 'variable.dart';
@ -12,7 +12,7 @@ class ValueOrVariableContext extends Node {
}
@override
SourceSpan get span => value?.span ?? variable.span;
FileSpan get span => value?.span ?? variable.span;
@override
String toSource() => '${value?.toSource() ?? variable.toSource()}';

View file

@ -1,6 +1,6 @@
import '../token.dart';
import 'node.dart';
import 'package:source_span/src/span.dart';
import 'package:source_span/source_span.dart';
class VariableContext extends Node {
final Token DOLLAR, NAME;
@ -10,8 +10,8 @@ class VariableContext extends Node {
String get name => NAME.text;
@override
SourceSpan get span => DOLLAR.span.union(NAME.span);
// new SourceSpan(DOLLAR?.span?.start, NAME?.span?.end, toSource());
FileSpan get span => DOLLAR.span.expand(NAME.span);
// new FileSpan(DOLLAR?.span?.start, NAME?.span?.end, toSource());
@override
String toSource() => '\$${NAME.text}';

View file

@ -1,7 +1,7 @@
import '../token.dart';
import 'node.dart';
import 'default_value.dart';
import 'package:source_span/src/span.dart';
import 'package:source_span/source_span.dart';
import 'type.dart';
import 'variable.dart';
@ -15,8 +15,7 @@ class VariableDefinitionContext extends Node {
[this.defaultValue]);
@override
SourceSpan get span =>
new SourceSpan(variable.start, defaultValue?.end ?? type.end, toSource());
FileSpan get span => variable.span.expand(defaultValue?.span ?? type.span);
@override
String toSource() =>

View file

@ -1,6 +1,6 @@
import '../token.dart';
import 'node.dart';
import 'package:source_span/src/span.dart';
import 'package:source_span/source_span.dart';
import 'variable_definition.dart';
class VariableDefinitionsContext extends Node {
@ -10,19 +10,22 @@ class VariableDefinitionsContext extends Node {
VariableDefinitionsContext(this.LPAREN, this.RPAREN);
@override
SourceSpan get span =>
new SourceSpan(LPAREN.span?.end, RPAREN.span?.end, toSource());
FileSpan get span {
var out = variableDefinitions.fold<FileSpan>(
LPAREN.span, (o, v) => o.expand(v.span));
return out.expand(RPAREN.span);
}
@override
String toSource() {
var buf = new StringBuffer('[');
var buf = new StringBuffer('(');
for (int i = 0; i < variableDefinitions.length; i++) {
if (i > 0) buf.write(',');
buf.write(variableDefinitions[i].toSource());
}
buf.write(']');
buf.write(')');
return buf.toString();
}
}

View file

@ -4,7 +4,7 @@ import 'token_type.dart';
class Token {
final TokenType type;
final String text;
SourceSpan span;
FileSpan span;
Token(this.type, this.text, [this.span]);

View file

@ -1,5 +1,5 @@
name: graphql_parser
version: 1.0.0
version: 1.0.0+1
description: Parses GraphQL queries and schemas.
author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/thosakwe/graphql_parser

View file

@ -39,6 +39,7 @@ class _IsArgument extends Matcher {
bool matches(item, Map matchState) {
var arg = item is ArgumentContext ? item : parseArgument(item);
if (arg == null) return false;
print(arg.toSource());
return equals(name).matches(arg.name, matchState) &&
equals(value).matches(
arg.valueOrVariable.value?.value ??

View file

@ -63,6 +63,7 @@ main() {
var doc =
parse(r'query foo ($one: [int] = 2) @foo @bar: 2 {foo, bar: baz}')
.parseDocument();
print(doc.toSource());
expect(doc.definitions, hasLength(1));
expect(doc.definitions.first,
const isInstanceOf<OperationDefinitionContext>());