Fixed disjoint spans
This commit is contained in:
parent
a059010428
commit
cfb509abea
30 changed files with 95 additions and 90 deletions
|
@ -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}';
|
||||
|
|
|
@ -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()}';
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()}';
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() =>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() =>
|
||||
|
|
|
@ -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()}]';
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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()}';
|
||||
|
|
|
@ -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}';
|
||||
|
|
|
@ -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() =>
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ??
|
||||
|
|
|
@ -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>());
|
||||
|
|
Loading…
Reference in a new issue