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

View file

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

View file

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

View file

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

View file

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

View file

@ -15,14 +15,16 @@ class DirectiveContext extends Node {
} }
@override @override
SourceSpan get span { FileSpan get span {
SourceLocation end = NAME.span?.end; var out = ARROBA.span.expand(NAME.span);
if (valueOrVariable != null) if (COLON != null) {
end = valueOrVariable.end; out = out.expand(COLON.span).expand(valueOrVariable.span);
else if (RPAREN != null) end = RPAREN.span?.end; } 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 @override

View file

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

View file

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

View file

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

View file

@ -1,7 +1,7 @@
import '../token.dart'; import '../token.dart';
import 'definition.dart'; import 'definition.dart';
import 'directive.dart'; import 'directive.dart';
import 'package:source_span/src/span.dart'; import 'package:source_span/source_span.dart';
import 'selection_set.dart'; import 'selection_set.dart';
import 'type_condition.dart'; import 'type_condition.dart';
@ -17,8 +17,14 @@ class FragmentDefinitionContext extends DefinitionContext {
this.FRAGMENT, this.NAME, this.ON, this.typeCondition, this.selectionSet); this.FRAGMENT, this.NAME, this.ON, this.typeCondition, this.selectionSet);
@override @override
SourceSpan get span => FileSpan get span {
new SourceSpan(FRAGMENT.span?.start, selectionSet.end, toSource()); 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 @override
String toSource() => String toSource() =>

View file

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

View file

@ -1,7 +1,7 @@
import '../token.dart'; import '../token.dart';
import 'directive.dart'; import 'directive.dart';
import 'node.dart'; import 'node.dart';
import 'package:source_span/src/span.dart'; import 'package:source_span/source_span.dart';
import 'selection_set.dart'; import 'selection_set.dart';
import 'type_condition.dart'; import 'type_condition.dart';
@ -15,8 +15,11 @@ class InlineFragmentContext extends Node {
this.ELLIPSIS, this.ON, this.typeCondition, this.selectionSet); this.ELLIPSIS, this.ON, this.typeCondition, this.selectionSet);
@override @override
SourceSpan get span => FileSpan get span {
new SourceSpan(ELLIPSIS.span?.start, selectionSet.end, toSource()); 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 @override
String toSource() => String toSource() =>

View file

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

View file

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

View file

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

View file

@ -1,7 +1,7 @@
import '../token.dart'; import '../token.dart';
import 'definition.dart'; import 'definition.dart';
import 'directive.dart'; import 'directive.dart';
import 'package:source_span/src/span.dart'; import 'package:source_span/source_span.dart';
import 'selection_set.dart'; import 'selection_set.dart';
import 'variable_definitions.dart'; import 'variable_definitions.dart';
@ -22,9 +22,11 @@ class OperationDefinitionContext extends DefinitionContext {
} }
@override @override
SourceSpan get span { FileSpan get span {
if (TYPE == null) return selectionSet.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 @override

View file

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

View file

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

View file

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

View file

@ -16,20 +16,9 @@ class TypeContext extends Node {
} }
@override @override
SourceSpan get span { FileSpan get span {
SourceLocation start, end; var out = typeName?.span ?? listType.span;
return EXCLAMATION != null ? out.expand(EXCLAMATION.span) : out;
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());
} }
@override @override

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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