summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormazza <128099384+mazza-av@users.noreply.github.com>2023-05-14 05:29:03 -0400
committerGitHub <noreply@github.com>2023-05-14 11:29:03 +0200
commit2401866e5afee0aa67fe5064a9ab41d06ecbde6d (patch)
tree0d389f38ac3b1fe3d8d3f4d9b00d390c31fe1fb8
parent9f9c907f24d9c7f847739b15597ddd86b7d0efd8 (diff)
downloadpygments-git-2401866e5afee0aa67fe5064a9ab41d06ecbde6d.tar.gz
Add support for GraphQL (#2428)
Co-authored-by: Jean Abou Samra <jean@abou-samra.fr>
-rw-r--r--pygments/lexers/_mapping.py1
-rw-r--r--pygments/lexers/graphql.py176
-rw-r--r--tests/examplefiles/graphql/ex01_field1.graphql5
-rw-r--r--tests/examplefiles/graphql/ex01_field1.graphql.output13
-rw-r--r--tests/examplefiles/graphql/ex02_field2.graphql9
-rw-r--r--tests/examplefiles/graphql/ex02_field2.graphql.output23
-rw-r--r--tests/examplefiles/graphql/ex03_arguments1.graphql6
-rw-r--r--tests/examplefiles/graphql/ex03_arguments1.graphql.output23
-rw-r--r--tests/examplefiles/graphql/ex04_arguments2.graphql6
-rw-r--r--tests/examplefiles/graphql/ex04_arguments2.graphql.output29
-rw-r--r--tests/examplefiles/graphql/ex05_aliases.graphql8
-rw-r--r--tests/examplefiles/graphql/ex05_aliases.graphql.output39
-rw-r--r--tests/examplefiles/graphql/ex06_fragments1.graphql16
-rw-r--r--tests/examplefiles/graphql/ex06_fragments1.graphql.output67
-rw-r--r--tests/examplefiles/graphql/ex07_fragments2.graphql20
-rw-r--r--tests/examplefiles/graphql/ex07_fragments2.graphql.output99
-rw-r--r--tests/examplefiles/graphql/ex08_operation_name.graphql8
-rw-r--r--tests/examplefiles/graphql/ex08_operation_name.graphql.output25
-rw-r--r--tests/examplefiles/graphql/ex09_variables1.graphql8
-rw-r--r--tests/examplefiles/graphql/ex09_variables1.graphql.output37
-rw-r--r--tests/examplefiles/graphql/ex10_variables2.graphql8
-rw-r--r--tests/examplefiles/graphql/ex10_variables2.graphql.output41
-rw-r--r--tests/examplefiles/graphql/ex11_directives.graphql8
-rw-r--r--tests/examplefiles/graphql/ex11_directives.graphql.output52
-rw-r--r--tests/examplefiles/graphql/ex12_mutations.graphql6
-rw-r--r--tests/examplefiles/graphql/ex12_mutations.graphql.output45
-rw-r--r--tests/examplefiles/graphql/ex13_inline_fragments1.graphql11
-rw-r--r--tests/examplefiles/graphql/ex13_inline_fragments1.graphql.output54
-rw-r--r--tests/examplefiles/graphql/ex14_inline_fragments2.graphql14
-rw-r--r--tests/examplefiles/graphql/ex14_inline_fragments2.graphql.output57
-rw-r--r--tests/test_graphql.py872
31 files changed, 1786 insertions, 0 deletions
diff --git a/pygments/lexers/_mapping.py b/pygments/lexers/_mapping.py
index 05e9b32f..cb28f176 100644
--- a/pygments/lexers/_mapping.py
+++ b/pygments/lexers/_mapping.py
@@ -190,6 +190,7 @@ LEXERS = {
'GoodDataCLLexer': ('pygments.lexers.business', 'GoodData-CL', ('gooddata-cl',), ('*.gdc',), ('text/x-gooddata-cl',)),
'GosuLexer': ('pygments.lexers.jvm', 'Gosu', ('gosu',), ('*.gs', '*.gsx', '*.gsp', '*.vark'), ('text/x-gosu',)),
'GosuTemplateLexer': ('pygments.lexers.jvm', 'Gosu Template', ('gst',), ('*.gst',), ('text/x-gosu-template',)),
+ 'GraphQLLexer': ('pygments.lexers.graphql', 'GraphQL', ('graphql',), ('*.graphql',), ()),
'GraphvizLexer': ('pygments.lexers.graphviz', 'Graphviz', ('graphviz', 'dot'), ('*.gv', '*.dot'), ('text/x-graphviz', 'text/vnd.graphviz')),
'GroffLexer': ('pygments.lexers.markup', 'Groff', ('groff', 'nroff', 'man'), ('*.[1-9]', '*.man', '*.1p', '*.3pm'), ('application/x-troff', 'text/troff')),
'GroovyLexer': ('pygments.lexers.jvm', 'Groovy', ('groovy',), ('*.groovy', '*.gradle'), ('text/x-groovy',)),
diff --git a/pygments/lexers/graphql.py b/pygments/lexers/graphql.py
new file mode 100644
index 00000000..4c09659b
--- /dev/null
+++ b/pygments/lexers/graphql.py
@@ -0,0 +1,176 @@
+"""
+ pygments.lexers.graphql
+ ~~~~~~~~~~~~~~~~~~~~~~~
+
+ Lexer for GraphQL, an open-source data query and manipulation
+ language for APIs.
+
+ More information:
+ https://graphql.org/
+
+ :copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+from pygments.lexer import RegexLexer, words, include, bygroups, default
+from pygments.token import (Comment, Keyword, Name, Number, Punctuation, String,
+ Whitespace)
+
+
+__all__ = ["GraphQLLexer"]
+
+OPERATION_TYPES = ("query", "mutation", "subscription")
+BUILTIN_TYPES = ("Int", "Float", "String", "Boolean", "ID")
+BOOLEAN_VALUES = ("true", "false", "null")
+KEYWORDS = (
+ "type",
+ "schema",
+ "extend",
+ "enum",
+ "scalar",
+ "implements",
+ "interface",
+ "union",
+ "input",
+ "directive",
+ "QUERY",
+ "MUTATION",
+ "SUBSCRIPTION",
+ "FIELD",
+ "FRAGMENT_DEFINITION",
+ "FRAGMENT_SPREAD",
+ "INLINE_FRAGMENT",
+ "SCHEMA",
+ "SCALAR",
+ "OBJECT",
+ "FIELD_DEFINITION",
+ "ARGUMENT_DEFINITION",
+ "INTERFACE",
+ "UNION",
+ "ENUM",
+ "ENUM_VALUE",
+ "INPUT_OBJECT",
+ "INPUT_FIELD_DEFINITION",
+)
+
+
+class GraphQLLexer(RegexLexer):
+ """
+ Lexer for GraphQL syntax
+
+ .. versionadded:: 2.15.1
+ """
+ name = "GraphQL"
+ aliases = ["graphql"]
+ filenames = ["*.graphql"]
+
+ tokens = {
+ "ignored_tokens": [
+ (r"\s+", Whitespace), # Whitespaces
+ (r"#.*$", Comment),
+ (",", Punctuation), # Insignificant commas
+ ],
+ "value": [
+ include("ignored_tokens"),
+ (r"-?\d+(?![.eE])", Number.Integer, "#pop"),
+ (
+ r"-?\d+(\.\d+)?([eE][+-]?\d+)?",
+ Number.Float,
+ "#pop",
+ ),
+ (r'"', String, ("#pop", "string")),
+ (words(BOOLEAN_VALUES, suffix=r"\b"), Name.Builtin, "#pop"),
+ (r"\$[a-zA-Z_]\w*", Name.Variable, "#pop"),
+ (r"[a-zA-Z_]\w*", Name.Constant, "#pop"),
+ (r"\[", Punctuation, ("#pop", "list_value")),
+ (r"\{", Punctuation, ("#pop", "object_value")),
+ ],
+ "list_value": [
+ include("ignored_tokens"),
+ ("]", Punctuation, "#pop"),
+ default("value"),
+ ],
+ "object_value": [
+ include("ignored_tokens"),
+ (r"[a-zA-Z_]\w*", Name),
+ (r":", Punctuation, "value"),
+ (r"\}", Punctuation, "#pop"),
+ ],
+ "string": [
+ (r'\\(["\\/bfnrt]|u[a-fA-F0-9]{4})', String.Escape),
+ (r'[^\\"\n]+', String), # all other characters
+ (r'"', String, "#pop"),
+ ],
+ "root": [
+ include("ignored_tokens"),
+ (words(OPERATION_TYPES, suffix=r"\b"), Keyword, "operation"),
+ (words(KEYWORDS, suffix=r"\b"), Keyword),
+ (r"\{", Punctuation, "selection_set"),
+ (r"fragment\b", Keyword, "fragment_definition"),
+ ],
+ "operation": [
+ include("ignored_tokens"),
+ (r"[a-zA-Z_]\w*", Name.Function),
+ (r"\(", Punctuation, "variable_definition"),
+ (r"\{", Punctuation, ("#pop", "selection_set")),
+ ],
+ "variable_definition": [
+ include("ignored_tokens"),
+ (r"\$[a-zA-Z_]\w*", Name.Variable),
+ (r"[\]!]", Punctuation),
+ (r":", Punctuation, "type"),
+ (r"=", Punctuation, "value"),
+ (r"\)", Punctuation, "#pop"),
+ ],
+ "type": [
+ include("ignored_tokens"),
+ (r"\[", Punctuation),
+ (words(BUILTIN_TYPES, suffix=r"\b"), Name.Builtin, "#pop"),
+ (r"[a-zA-Z_]\w*", Name.Class, "#pop"),
+ ],
+ "selection_set": [
+ include("ignored_tokens"),
+ (r"([a-zA-Z_]\w*)(\s*)(:)", bygroups(Name.Label, Whitespace, Punctuation)),
+ (r"[a-zA-Z_]\w*", Name), # Field
+ (
+ r"(\.\.\.)(\s+)(on)\b",
+ bygroups(Punctuation, Whitespace, Keyword),
+ "inline_fragment",
+ ),
+ (r"\.\.\.", Punctuation, "fragment_spread"),
+ (r"\(", Punctuation, "arguments"),
+ (r"@[a-zA-Z_]\w*", Name.Decorator, "directive"),
+ (r"\{", Punctuation, "selection_set"),
+ (r"\}", Punctuation, "#pop"),
+ ],
+ "directive": [
+ include("ignored_tokens"),
+ (r"\(", Punctuation, ("#pop", "arguments")),
+ ],
+ "arguments": [
+ include("ignored_tokens"),
+ (r"[a-zA-Z_]\w*", Name),
+ (r":", Punctuation, "value"),
+ (r"\)", Punctuation, "#pop"),
+ ],
+ # Fragments
+ "fragment_definition": [
+ include("ignored_tokens"),
+ (r"[\]!]", Punctuation), # For NamedType
+ (r"on\b", Keyword, "type"),
+ (r"[a-zA-Z_]\w*", Name.Function),
+ (r"@[a-zA-Z_]\w*", Name.Decorator, "directive"),
+ (r"\{", Punctuation, ("#pop", "selection_set")),
+ ],
+ "fragment_spread": [
+ include("ignored_tokens"),
+ (r"@[a-zA-Z_]\w*", Name.Decorator, "directive"),
+ (r"[a-zA-Z_]\w*", Name, "#pop"), # Fragment name
+ ],
+ "inline_fragment": [
+ include("ignored_tokens"),
+ (r"[a-zA-Z_]\w*", Name.Class), # Type condition
+ (r"@[a-zA-Z_]\w*", Name.Decorator, "directive"),
+ (r"\{", Punctuation, ("#pop", "selection_set")),
+ ],
+ }
diff --git a/tests/examplefiles/graphql/ex01_field1.graphql b/tests/examplefiles/graphql/ex01_field1.graphql
new file mode 100644
index 00000000..d4aef93a
--- /dev/null
+++ b/tests/examplefiles/graphql/ex01_field1.graphql
@@ -0,0 +1,5 @@
+{
+ hero {
+ name
+ }
+}
diff --git a/tests/examplefiles/graphql/ex01_field1.graphql.output b/tests/examplefiles/graphql/ex01_field1.graphql.output
new file mode 100644
index 00000000..ae18503a
--- /dev/null
+++ b/tests/examplefiles/graphql/ex01_field1.graphql.output
@@ -0,0 +1,13 @@
+'{' Punctuation
+'\n ' Text.Whitespace
+'hero' Name
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'name' Name
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n' Text.Whitespace
+
+'}' Punctuation
+'\n' Text.Whitespace
diff --git a/tests/examplefiles/graphql/ex02_field2.graphql b/tests/examplefiles/graphql/ex02_field2.graphql
new file mode 100644
index 00000000..68f1695b
--- /dev/null
+++ b/tests/examplefiles/graphql/ex02_field2.graphql
@@ -0,0 +1,9 @@
+{
+ hero {
+ name
+ # Queries can have comments!
+ friends {
+ name
+ }
+ }
+}
diff --git a/tests/examplefiles/graphql/ex02_field2.graphql.output b/tests/examplefiles/graphql/ex02_field2.graphql.output
new file mode 100644
index 00000000..dcdb8cc9
--- /dev/null
+++ b/tests/examplefiles/graphql/ex02_field2.graphql.output
@@ -0,0 +1,23 @@
+'{' Punctuation
+'\n ' Text.Whitespace
+'hero' Name
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'name' Name
+'\n ' Text.Whitespace
+'# Queries can have comments!' Comment
+'\n ' Text.Whitespace
+'friends' Name
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'name' Name
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n' Text.Whitespace
+
+'}' Punctuation
+'\n' Text.Whitespace
diff --git a/tests/examplefiles/graphql/ex03_arguments1.graphql b/tests/examplefiles/graphql/ex03_arguments1.graphql
new file mode 100644
index 00000000..e46bcbe2
--- /dev/null
+++ b/tests/examplefiles/graphql/ex03_arguments1.graphql
@@ -0,0 +1,6 @@
+{
+ human(id: "1000") {
+ name
+ height
+ }
+}
diff --git a/tests/examplefiles/graphql/ex03_arguments1.graphql.output b/tests/examplefiles/graphql/ex03_arguments1.graphql.output
new file mode 100644
index 00000000..78f86964
--- /dev/null
+++ b/tests/examplefiles/graphql/ex03_arguments1.graphql.output
@@ -0,0 +1,23 @@
+'{' Punctuation
+'\n ' Text.Whitespace
+'human' Name
+'(' Punctuation
+'id' Name
+':' Punctuation
+' ' Text.Whitespace
+'"' Literal.String
+'1000' Literal.String
+'"' Literal.String
+')' Punctuation
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'name' Name
+'\n ' Text.Whitespace
+'height' Name
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n' Text.Whitespace
+
+'}' Punctuation
+'\n' Text.Whitespace
diff --git a/tests/examplefiles/graphql/ex04_arguments2.graphql b/tests/examplefiles/graphql/ex04_arguments2.graphql
new file mode 100644
index 00000000..f406f637
--- /dev/null
+++ b/tests/examplefiles/graphql/ex04_arguments2.graphql
@@ -0,0 +1,6 @@
+{
+ human(id: "1000") {
+ name
+ height(unit: FOOT)
+ }
+}
diff --git a/tests/examplefiles/graphql/ex04_arguments2.graphql.output b/tests/examplefiles/graphql/ex04_arguments2.graphql.output
new file mode 100644
index 00000000..472a2ed8
--- /dev/null
+++ b/tests/examplefiles/graphql/ex04_arguments2.graphql.output
@@ -0,0 +1,29 @@
+'{' Punctuation
+'\n ' Text.Whitespace
+'human' Name
+'(' Punctuation
+'id' Name
+':' Punctuation
+' ' Text.Whitespace
+'"' Literal.String
+'1000' Literal.String
+'"' Literal.String
+')' Punctuation
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'name' Name
+'\n ' Text.Whitespace
+'height' Name
+'(' Punctuation
+'unit' Name
+':' Punctuation
+' ' Text.Whitespace
+'FOOT' Name.Constant
+')' Punctuation
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n' Text.Whitespace
+
+'}' Punctuation
+'\n' Text.Whitespace
diff --git a/tests/examplefiles/graphql/ex05_aliases.graphql b/tests/examplefiles/graphql/ex05_aliases.graphql
new file mode 100644
index 00000000..a21db69e
--- /dev/null
+++ b/tests/examplefiles/graphql/ex05_aliases.graphql
@@ -0,0 +1,8 @@
+{
+ empireHero: hero(episode: EMPIRE) {
+ name
+ }
+ jediHero: hero(episode: JEDI) {
+ name
+ }
+}
diff --git a/tests/examplefiles/graphql/ex05_aliases.graphql.output b/tests/examplefiles/graphql/ex05_aliases.graphql.output
new file mode 100644
index 00000000..1f4dcead
--- /dev/null
+++ b/tests/examplefiles/graphql/ex05_aliases.graphql.output
@@ -0,0 +1,39 @@
+'{' Punctuation
+'\n ' Text.Whitespace
+'empireHero' Name.Label
+':' Punctuation
+' ' Text.Whitespace
+'hero' Name
+'(' Punctuation
+'episode' Name
+':' Punctuation
+' ' Text.Whitespace
+'EMPIRE' Name.Constant
+')' Punctuation
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'name' Name
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n ' Text.Whitespace
+'jediHero' Name.Label
+':' Punctuation
+' ' Text.Whitespace
+'hero' Name
+'(' Punctuation
+'episode' Name
+':' Punctuation
+' ' Text.Whitespace
+'JEDI' Name.Constant
+')' Punctuation
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'name' Name
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n' Text.Whitespace
+
+'}' Punctuation
+'\n' Text.Whitespace
diff --git a/tests/examplefiles/graphql/ex06_fragments1.graphql b/tests/examplefiles/graphql/ex06_fragments1.graphql
new file mode 100644
index 00000000..7c2783e7
--- /dev/null
+++ b/tests/examplefiles/graphql/ex06_fragments1.graphql
@@ -0,0 +1,16 @@
+{
+ leftComparison: hero(episode: EMPIRE) {
+ ...comparisonFields
+ }
+ rightComparison: hero(episode: JEDI) {
+ ...comparisonFields
+ }
+}
+
+fragment comparisonFields on Character {
+ name
+ appearsIn
+ friends {
+ name
+ }
+}
diff --git a/tests/examplefiles/graphql/ex06_fragments1.graphql.output b/tests/examplefiles/graphql/ex06_fragments1.graphql.output
new file mode 100644
index 00000000..76c0af07
--- /dev/null
+++ b/tests/examplefiles/graphql/ex06_fragments1.graphql.output
@@ -0,0 +1,67 @@
+'{' Punctuation
+'\n ' Text.Whitespace
+'leftComparison' Name.Label
+':' Punctuation
+' ' Text.Whitespace
+'hero' Name
+'(' Punctuation
+'episode' Name
+':' Punctuation
+' ' Text.Whitespace
+'EMPIRE' Name.Constant
+')' Punctuation
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'...' Punctuation
+'comparisonFields' Name
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n ' Text.Whitespace
+'rightComparison' Name.Label
+':' Punctuation
+' ' Text.Whitespace
+'hero' Name
+'(' Punctuation
+'episode' Name
+':' Punctuation
+' ' Text.Whitespace
+'JEDI' Name.Constant
+')' Punctuation
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'...' Punctuation
+'comparisonFields' Name
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n' Text.Whitespace
+
+'}' Punctuation
+'\n\n' Text.Whitespace
+
+'fragment' Keyword
+' ' Text.Whitespace
+'comparisonFields' Name.Function
+' ' Text.Whitespace
+'on' Keyword
+' ' Text.Whitespace
+'Character' Name.Class
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'name' Name
+'\n ' Text.Whitespace
+'appearsIn' Name
+'\n ' Text.Whitespace
+'friends' Name
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'name' Name
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n' Text.Whitespace
+
+'}' Punctuation
+'\n' Text.Whitespace
diff --git a/tests/examplefiles/graphql/ex07_fragments2.graphql b/tests/examplefiles/graphql/ex07_fragments2.graphql
new file mode 100644
index 00000000..f9294954
--- /dev/null
+++ b/tests/examplefiles/graphql/ex07_fragments2.graphql
@@ -0,0 +1,20 @@
+query HeroComparison($first: Int = 3) {
+ leftComparison: hero(episode: EMPIRE) {
+ ...comparisonFields
+ }
+ rightComparison: hero(episode: JEDI) {
+ ...comparisonFields
+ }
+}
+
+fragment comparisonFields on Character {
+ name
+ friendsConnection(first: $first) {
+ totalCount
+ edges {
+ node {
+ name
+ }
+ }
+ }
+}
diff --git a/tests/examplefiles/graphql/ex07_fragments2.graphql.output b/tests/examplefiles/graphql/ex07_fragments2.graphql.output
new file mode 100644
index 00000000..2ee8e6cd
--- /dev/null
+++ b/tests/examplefiles/graphql/ex07_fragments2.graphql.output
@@ -0,0 +1,99 @@
+'query' Keyword
+' ' Text.Whitespace
+'HeroComparison' Name.Function
+'(' Punctuation
+'$first' Name.Variable
+':' Punctuation
+' ' Text.Whitespace
+'Int' Name.Builtin
+' ' Text.Whitespace
+'=' Punctuation
+' ' Text.Whitespace
+'3' Literal.Number.Integer
+')' Punctuation
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'leftComparison' Name.Label
+':' Punctuation
+' ' Text.Whitespace
+'hero' Name
+'(' Punctuation
+'episode' Name
+':' Punctuation
+' ' Text.Whitespace
+'EMPIRE' Name.Constant
+')' Punctuation
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'...' Punctuation
+'comparisonFields' Name
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n ' Text.Whitespace
+'rightComparison' Name.Label
+':' Punctuation
+' ' Text.Whitespace
+'hero' Name
+'(' Punctuation
+'episode' Name
+':' Punctuation
+' ' Text.Whitespace
+'JEDI' Name.Constant
+')' Punctuation
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'...' Punctuation
+'comparisonFields' Name
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n' Text.Whitespace
+
+'}' Punctuation
+'\n\n' Text.Whitespace
+
+'fragment' Keyword
+' ' Text.Whitespace
+'comparisonFields' Name.Function
+' ' Text.Whitespace
+'on' Keyword
+' ' Text.Whitespace
+'Character' Name.Class
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'name' Name
+'\n ' Text.Whitespace
+'friendsConnection' Name
+'(' Punctuation
+'first' Name
+':' Punctuation
+' ' Text.Whitespace
+'$first' Name.Variable
+')' Punctuation
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'totalCount' Name
+'\n ' Text.Whitespace
+'edges' Name
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'node' Name
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'name' Name
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n' Text.Whitespace
+
+'}' Punctuation
+'\n' Text.Whitespace
diff --git a/tests/examplefiles/graphql/ex08_operation_name.graphql b/tests/examplefiles/graphql/ex08_operation_name.graphql
new file mode 100644
index 00000000..13c21a62
--- /dev/null
+++ b/tests/examplefiles/graphql/ex08_operation_name.graphql
@@ -0,0 +1,8 @@
+query HeroNameAndFriends {
+ hero {
+ name
+ friends {
+ name
+ }
+ }
+}
diff --git a/tests/examplefiles/graphql/ex08_operation_name.graphql.output b/tests/examplefiles/graphql/ex08_operation_name.graphql.output
new file mode 100644
index 00000000..eacc529e
--- /dev/null
+++ b/tests/examplefiles/graphql/ex08_operation_name.graphql.output
@@ -0,0 +1,25 @@
+'query' Keyword
+' ' Text.Whitespace
+'HeroNameAndFriends' Name.Function
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'hero' Name
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'name' Name
+'\n ' Text.Whitespace
+'friends' Name
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'name' Name
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n' Text.Whitespace
+
+'}' Punctuation
+'\n' Text.Whitespace
diff --git a/tests/examplefiles/graphql/ex09_variables1.graphql b/tests/examplefiles/graphql/ex09_variables1.graphql
new file mode 100644
index 00000000..5f0f4ef1
--- /dev/null
+++ b/tests/examplefiles/graphql/ex09_variables1.graphql
@@ -0,0 +1,8 @@
+query HeroNameAndFriends($episode: Episode) {
+ hero(episode: $episode) {
+ name
+ friends {
+ name
+ }
+ }
+}
diff --git a/tests/examplefiles/graphql/ex09_variables1.graphql.output b/tests/examplefiles/graphql/ex09_variables1.graphql.output
new file mode 100644
index 00000000..8d6bdd9f
--- /dev/null
+++ b/tests/examplefiles/graphql/ex09_variables1.graphql.output
@@ -0,0 +1,37 @@
+'query' Keyword
+' ' Text.Whitespace
+'HeroNameAndFriends' Name.Function
+'(' Punctuation
+'$episode' Name.Variable
+':' Punctuation
+' ' Text.Whitespace
+'Episode' Name.Class
+')' Punctuation
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'hero' Name
+'(' Punctuation
+'episode' Name
+':' Punctuation
+' ' Text.Whitespace
+'$episode' Name.Variable
+')' Punctuation
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'name' Name
+'\n ' Text.Whitespace
+'friends' Name
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'name' Name
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n' Text.Whitespace
+
+'}' Punctuation
+'\n' Text.Whitespace
diff --git a/tests/examplefiles/graphql/ex10_variables2.graphql b/tests/examplefiles/graphql/ex10_variables2.graphql
new file mode 100644
index 00000000..3db6cc71
--- /dev/null
+++ b/tests/examplefiles/graphql/ex10_variables2.graphql
@@ -0,0 +1,8 @@
+query HeroNameAndFriends($episode: Episode = JEDI) {
+ hero(episode: $episode) {
+ name
+ friends {
+ name
+ }
+ }
+}
diff --git a/tests/examplefiles/graphql/ex10_variables2.graphql.output b/tests/examplefiles/graphql/ex10_variables2.graphql.output
new file mode 100644
index 00000000..751cdc8a
--- /dev/null
+++ b/tests/examplefiles/graphql/ex10_variables2.graphql.output
@@ -0,0 +1,41 @@
+'query' Keyword
+' ' Text.Whitespace
+'HeroNameAndFriends' Name.Function
+'(' Punctuation
+'$episode' Name.Variable
+':' Punctuation
+' ' Text.Whitespace
+'Episode' Name.Class
+' ' Text.Whitespace
+'=' Punctuation
+' ' Text.Whitespace
+'JEDI' Name.Constant
+')' Punctuation
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'hero' Name
+'(' Punctuation
+'episode' Name
+':' Punctuation
+' ' Text.Whitespace
+'$episode' Name.Variable
+')' Punctuation
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'name' Name
+'\n ' Text.Whitespace
+'friends' Name
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'name' Name
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n' Text.Whitespace
+
+'}' Punctuation
+'\n' Text.Whitespace
diff --git a/tests/examplefiles/graphql/ex11_directives.graphql b/tests/examplefiles/graphql/ex11_directives.graphql
new file mode 100644
index 00000000..9f0b76f1
--- /dev/null
+++ b/tests/examplefiles/graphql/ex11_directives.graphql
@@ -0,0 +1,8 @@
+query Hero($episode: Episode, $withFriends: Boolean!) {
+ hero(episode: $episode) {
+ name
+ friends @include(if: $withFriends) {
+ name
+ }
+ }
+}
diff --git a/tests/examplefiles/graphql/ex11_directives.graphql.output b/tests/examplefiles/graphql/ex11_directives.graphql.output
new file mode 100644
index 00000000..486b87c4
--- /dev/null
+++ b/tests/examplefiles/graphql/ex11_directives.graphql.output
@@ -0,0 +1,52 @@
+'query' Keyword
+' ' Text.Whitespace
+'Hero' Name.Function
+'(' Punctuation
+'$episode' Name.Variable
+':' Punctuation
+' ' Text.Whitespace
+'Episode' Name.Class
+',' Punctuation
+' ' Text.Whitespace
+'$withFriends' Name.Variable
+':' Punctuation
+' ' Text.Whitespace
+'Boolean' Name.Builtin
+'!' Punctuation
+')' Punctuation
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'hero' Name
+'(' Punctuation
+'episode' Name
+':' Punctuation
+' ' Text.Whitespace
+'$episode' Name.Variable
+')' Punctuation
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'name' Name
+'\n ' Text.Whitespace
+'friends' Name
+' ' Text.Whitespace
+'@include' Name.Decorator
+'(' Punctuation
+'if' Name
+':' Punctuation
+' ' Text.Whitespace
+'$withFriends' Name.Variable
+')' Punctuation
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'name' Name
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n' Text.Whitespace
+
+'}' Punctuation
+'\n' Text.Whitespace
diff --git a/tests/examplefiles/graphql/ex12_mutations.graphql b/tests/examplefiles/graphql/ex12_mutations.graphql
new file mode 100644
index 00000000..c82d383d
--- /dev/null
+++ b/tests/examplefiles/graphql/ex12_mutations.graphql
@@ -0,0 +1,6 @@
+mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
+ createReview(episode: $ep, review: $review) {
+ stars
+ commentary
+ }
+}
diff --git a/tests/examplefiles/graphql/ex12_mutations.graphql.output b/tests/examplefiles/graphql/ex12_mutations.graphql.output
new file mode 100644
index 00000000..5d6def44
--- /dev/null
+++ b/tests/examplefiles/graphql/ex12_mutations.graphql.output
@@ -0,0 +1,45 @@
+'mutation' Keyword
+' ' Text.Whitespace
+'CreateReviewForEpisode' Name.Function
+'(' Punctuation
+'$ep' Name.Variable
+':' Punctuation
+' ' Text.Whitespace
+'Episode' Name.Class
+'!' Punctuation
+',' Punctuation
+' ' Text.Whitespace
+'$review' Name.Variable
+':' Punctuation
+' ' Text.Whitespace
+'ReviewInput' Name.Class
+'!' Punctuation
+')' Punctuation
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'createReview' Name
+'(' Punctuation
+'episode' Name
+':' Punctuation
+' ' Text.Whitespace
+'$ep' Name.Variable
+',' Punctuation
+' ' Text.Whitespace
+'review' Name
+':' Punctuation
+' ' Text.Whitespace
+'$review' Name.Variable
+')' Punctuation
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'stars' Name
+'\n ' Text.Whitespace
+'commentary' Name
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n' Text.Whitespace
+
+'}' Punctuation
+'\n' Text.Whitespace
diff --git a/tests/examplefiles/graphql/ex13_inline_fragments1.graphql b/tests/examplefiles/graphql/ex13_inline_fragments1.graphql
new file mode 100644
index 00000000..df261926
--- /dev/null
+++ b/tests/examplefiles/graphql/ex13_inline_fragments1.graphql
@@ -0,0 +1,11 @@
+query HeroForEpisode($ep: Episode!) {
+ hero(episode: $ep) {
+ name
+ ... on Droid {
+ primaryFunction
+ }
+ ... on Human {
+ height
+ }
+ }
+}
diff --git a/tests/examplefiles/graphql/ex13_inline_fragments1.graphql.output b/tests/examplefiles/graphql/ex13_inline_fragments1.graphql.output
new file mode 100644
index 00000000..16348903
--- /dev/null
+++ b/tests/examplefiles/graphql/ex13_inline_fragments1.graphql.output
@@ -0,0 +1,54 @@
+'query' Keyword
+' ' Text.Whitespace
+'HeroForEpisode' Name.Function
+'(' Punctuation
+'$ep' Name.Variable
+':' Punctuation
+' ' Text.Whitespace
+'Episode' Name.Class
+'!' Punctuation
+')' Punctuation
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'hero' Name
+'(' Punctuation
+'episode' Name
+':' Punctuation
+' ' Text.Whitespace
+'$ep' Name.Variable
+')' Punctuation
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'name' Name
+'\n ' Text.Whitespace
+'...' Punctuation
+' ' Text.Whitespace
+'on' Keyword
+' ' Text.Whitespace
+'Droid' Name.Class
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'primaryFunction' Name
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n ' Text.Whitespace
+'...' Punctuation
+' ' Text.Whitespace
+'on' Keyword
+' ' Text.Whitespace
+'Human' Name.Class
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'height' Name
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n' Text.Whitespace
+
+'}' Punctuation
+'\n' Text.Whitespace
diff --git a/tests/examplefiles/graphql/ex14_inline_fragments2.graphql b/tests/examplefiles/graphql/ex14_inline_fragments2.graphql
new file mode 100644
index 00000000..f756edc4
--- /dev/null
+++ b/tests/examplefiles/graphql/ex14_inline_fragments2.graphql
@@ -0,0 +1,14 @@
+{
+ search(text: "an") {
+ __typename
+ ... on Human {
+ name
+ }
+ ... on Droid {
+ name
+ }
+ ... on Starship {
+ name
+ }
+ }
+}
diff --git a/tests/examplefiles/graphql/ex14_inline_fragments2.graphql.output b/tests/examplefiles/graphql/ex14_inline_fragments2.graphql.output
new file mode 100644
index 00000000..2cfca433
--- /dev/null
+++ b/tests/examplefiles/graphql/ex14_inline_fragments2.graphql.output
@@ -0,0 +1,57 @@
+'{' Punctuation
+'\n ' Text.Whitespace
+'search' Name
+'(' Punctuation
+'text' Name
+':' Punctuation
+' ' Text.Whitespace
+'"' Literal.String
+'an' Literal.String
+'"' Literal.String
+')' Punctuation
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'__typename' Name
+'\n ' Text.Whitespace
+'...' Punctuation
+' ' Text.Whitespace
+'on' Keyword
+' ' Text.Whitespace
+'Human' Name.Class
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'name' Name
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n ' Text.Whitespace
+'...' Punctuation
+' ' Text.Whitespace
+'on' Keyword
+' ' Text.Whitespace
+'Droid' Name.Class
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'name' Name
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n ' Text.Whitespace
+'...' Punctuation
+' ' Text.Whitespace
+'on' Keyword
+' ' Text.Whitespace
+'Starship' Name.Class
+' ' Text.Whitespace
+'{' Punctuation
+'\n ' Text.Whitespace
+'name' Name
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n ' Text.Whitespace
+'}' Punctuation
+'\n' Text.Whitespace
+
+'}' Punctuation
+'\n' Text.Whitespace
diff --git a/tests/test_graphql.py b/tests/test_graphql.py
new file mode 100644
index 00000000..8e64f68a
--- /dev/null
+++ b/tests/test_graphql.py
@@ -0,0 +1,872 @@
+import unittest
+import textwrap
+
+from pygments.lexers import GraphQLLexer
+from pygments.token import (
+ Comment,
+ Error,
+ Keyword,
+ Name,
+ Number,
+ Punctuation,
+ String,
+ Whitespace
+)
+
+
+def assert_tokens_equal(self, text, expected, stack=("root",)):
+ text = textwrap.dedent(text)
+ lexer = GraphQLLexer()
+ tokens_itr = lexer.get_tokens_unprocessed(text, stack=stack)
+ self.assertEqual(list(tokens_itr), expected)
+
+
+def assert_value_equal(self, text, expected):
+ if not isinstance(expected, list):
+ expected = [expected]
+ assert_tokens_equal(self, text, expected, stack=("value",))
+
+
+def assert_string_equal(self, text, tokens):
+ start = (0, String, '"')
+ end = (len(text) - 1, String, '"')
+ expected = [start, *tokens, end]
+ assert_tokens_equal(self, text, expected, stack=("value",))
+
+
+class TestValue(unittest.TestCase):
+
+ maxDiff = None
+
+ def test_float(self):
+ assert_value_equal(self, "5.5", (0, Number.Float, "5.5"))
+ assert_value_equal(self, "5e3", (0, Number.Float, "5e3"))
+ assert_value_equal(self, "5E3", (0, Number.Float, "5E3"))
+ assert_value_equal(self, "5e-3", (0, Number.Float, "5e-3"))
+ assert_value_equal(self, "5E-3", (0, Number.Float, "5E-3"))
+ assert_value_equal(self, "5e+3", (0, Number.Float, "5e+3"))
+ assert_value_equal(self, "5E+3", (0, Number.Float, "5E+3"))
+ assert_value_equal(self, "5.1e3", (0, Number.Float, "5.1e3"))
+ assert_value_equal(self, "5.1E3", (0, Number.Float, "5.1E3"))
+ assert_value_equal(self, "5.1e-3", (0, Number.Float, "5.1e-3"))
+ assert_value_equal(self, "5.1E-3", (0, Number.Float, "5.1E-3"))
+ assert_value_equal(self, "5.1e+3", (0, Number.Float, "5.1e+3"))
+ assert_value_equal(self, "5.1E+3", (0, Number.Float, "5.1E+3"))
+
+ def test_integer(self):
+ assert_value_equal(self, "5", (0, Number.Integer, "5"))
+ assert_value_equal(self, "-0", (0, Number.Integer, "-0"))
+ # Not really following the specifications
+ assert_value_equal(self, "-02", (0, Number.Integer, "-02"))
+
+ def test_string(self):
+ assert_string_equal(self, '"asdf"', [(1, String, "asdf")])
+ assert_string_equal(
+ self,
+ r'"asdf\""',
+ [
+ (1, String, "asdf"),
+ (5, String.Escape, r"\""),
+ ],
+ )
+ assert_string_equal(
+ self, r'"asdf\m"', [(1, String, "asdf"), (5, Error, "\\"), (6, String, "m")]
+ )
+ assert_string_equal(
+ self,
+ r'"asdf\u00E8"',
+ [
+ (1, String, "asdf"),
+ (5, String.Escape, r"\u00E8"),
+ ],
+ )
+
+ def test_boolean(self):
+ assert_value_equal(self, "true", (0, Name.Builtin, "true"))
+ assert_value_equal(self, "false", (0, Name.Builtin, "false"))
+
+ def test_variable(self):
+ assert_value_equal(self, "$hello", (0, Name.Variable, "$hello"))
+ assert_value_equal(
+ self,
+ "$0hello",
+ [
+ (0, Error, "$"),
+ (1, Number.Integer, "0"),
+ (2, Name.Constant, "hello"),
+ ],
+ )
+
+ def test_list_value(self):
+ assert_value_equal(
+ self,
+ '[1, 1.1, "abc"]',
+ [
+ (0, Punctuation, "["),
+ (1, Number.Integer, "1"),
+ (2, Punctuation, ","),
+ (3, Whitespace, " "),
+ (4, Number.Float, "1.1"),
+ (7, Punctuation, ","),
+ (8, Whitespace, " "),
+ (9, String, '"'),
+ (10, String, "abc"),
+ (13, String, '"'),
+ (14, Punctuation, "]"),
+ ],
+ )
+ assert_value_equal(
+ self,
+ '[1, 1.1, ["abc"]]',
+ [
+ (0, Punctuation, "["),
+ (1, Number.Integer, "1"),
+ (2, Punctuation, ","),
+ (3, Whitespace, " "),
+ (4, Number.Float, "1.1"),
+ (7, Punctuation, ","),
+ (8, Whitespace, " "),
+ (9, Punctuation, "["),
+ (10, String, '"'),
+ (11, String, "abc"),
+ (14, String, '"'),
+ (15, Punctuation, "]"),
+ (16, Punctuation, "]"),
+ ],
+ )
+
+
+class TestGraphqlLexer(unittest.TestCase):
+
+ maxDiff = None
+
+ def assert_builtin(self, text):
+ assert_tokens_equal(self, text, [(0, Name.Builtin, text)], stack=("builtins",))
+
+ def test_keyworkd(self):
+ assert_tokens_equal(self, "type", [(0, Keyword, "type")])
+ assert_tokens_equal(self, "schema", [(0, Keyword, "schema")])
+ assert_tokens_equal(self, "extend", [(0, Keyword, "extend")])
+ assert_tokens_equal(self, "enum", [(0, Keyword, "enum")])
+ assert_tokens_equal(self, "scalar", [(0, Keyword, "scalar")])
+ assert_tokens_equal(self, "implements", [(0, Keyword, "implements")])
+ assert_tokens_equal(self, "interface", [(0, Keyword, "interface")])
+ assert_tokens_equal(self, "union", [(0, Keyword, "union")])
+ assert_tokens_equal(self, "input", [(0, Keyword, "input")])
+ assert_tokens_equal(self, "directive", [(0, Keyword, "directive")])
+
+ def test_arguments_integer(self):
+ text = """\
+ {
+ field(arg: 24)
+ field
+ }
+ """
+
+ expected = [
+ (0, Punctuation, "{"),
+ (1, Whitespace, "\n "),
+ (4, Name, "field"),
+ (9, Punctuation, "("),
+ (10, Name, "arg"),
+ # (10, Name.Attribute, 'arg'),
+ (13, Punctuation, ":"),
+ (14, Whitespace, " "),
+ (15, Number.Integer, "24"),
+ (17, Punctuation, ")"),
+ (18, Whitespace, "\n "),
+ (21, Name, "field"),
+ (26, Whitespace, "\n"),
+ (27, Punctuation, "}"),
+ (28, Whitespace, "\n"),
+ ]
+ assert_tokens_equal(self, text, expected)
+
+ def test_arguments(self):
+ text = """\
+ {
+ human(id: "1000") {
+ name
+ height
+ }
+ }
+ """
+ expected = [
+ (0, Punctuation, "{"),
+ (1, Whitespace, "\n "),
+ (4, Name, "human"),
+ (9, Punctuation, "("),
+ # (10, Name.Attribute, 'id'),
+ (10, Name, "id"),
+ (12, Punctuation, ":"),
+ (13, Whitespace, " "),
+ (14, String, '"'),
+ (15, String, "1000"),
+ (19, String, '"'),
+ (20, Punctuation, ")"),
+ (21, Whitespace, " "),
+ (22, Punctuation, "{"),
+ (23, Whitespace, "\n "),
+ (28, Name, "name"),
+ (32, Whitespace, "\n "),
+ (37, Name, "height"),
+ (43, Whitespace, "\n "),
+ (46, Punctuation, "}"),
+ (47, Whitespace, "\n"),
+ (48, Punctuation, "}"),
+ (49, Whitespace, "\n"),
+ ]
+ assert_tokens_equal(self, text, expected)
+
+ def test_argument_scalar(self):
+ text = """\
+ {
+ human(id: "1000") {
+ name
+ height(unit: FOOT)
+ }
+ }
+ """
+ expected = [
+ (0, Punctuation, "{"),
+ (1, Whitespace, "\n "),
+ (4, Name, "human"),
+ (9, Punctuation, "("),
+ # (10, Name.Attribute, 'id'),
+ (10, Name, "id"),
+ (12, Punctuation, ":"),
+ (13, Whitespace, " "),
+ (14, String, '"'),
+ (15, String, "1000"),
+ (19, String, '"'),
+ (20, Punctuation, ")"),
+ (21, Whitespace, " "),
+ (22, Punctuation, "{"),
+ (23, Whitespace, "\n "),
+ (28, Name, "name"),
+ (32, Whitespace, "\n "),
+ (37, Name, "height"),
+ (43, Punctuation, "("),
+ # (44, Name.Attribute, 'unit'),
+ (44, Name, "unit"),
+ (48, Punctuation, ":"),
+ (49, Whitespace, " "),
+ (50, Name.Constant, "FOOT"),
+ (54, Punctuation, ")"),
+ (55, Whitespace, "\n "),
+ (58, Punctuation, "}"),
+ (59, Whitespace, "\n"),
+ (60, Punctuation, "}"),
+ (61, Whitespace, "\n"),
+ ]
+ assert_tokens_equal(self, text, expected)
+
+ def test_alias(self):
+ text = """\
+ {
+ empireHero: hero(episode: EMPIRE) {
+ name
+ }
+ jediHero: hero(episode: JEDI) {
+ name
+ }
+ }
+ """
+ expected = [
+ (0, Punctuation, "{"),
+ (1, Whitespace, "\n "),
+ (4, Name.Label, "empireHero"),
+ (14, Punctuation, ":"),
+ (15, Whitespace, " "),
+ (16, Name, "hero"),
+ (20, Punctuation, "("),
+ # (21, Name.Attribute, 'episode'),
+ (21, Name, "episode"),
+ (28, Punctuation, ":"),
+ (29, Whitespace, " "),
+ (30, Name.Constant, "EMPIRE"),
+ (36, Punctuation, ")"),
+ (37, Whitespace, " "),
+ (38, Punctuation, "{"),
+ (39, Whitespace, "\n "),
+ (44, Name, "name"),
+ (48, Whitespace, "\n "),
+ (51, Punctuation, "}"),
+ (52, Whitespace, "\n "),
+ (55, Name.Label, "jediHero"),
+ (63, Punctuation, ":"),
+ (64, Whitespace, " "),
+ (65, Name, "hero"),
+ (69, Punctuation, "("),
+ # (70, Name.Attribute, 'episode'),
+ (70, Name, "episode"),
+ (77, Punctuation, ":"),
+ (78, Whitespace, " "),
+ (79, Name.Constant, "JEDI"),
+ (83, Punctuation, ")"),
+ (84, Whitespace, " "),
+ (85, Punctuation, "{"),
+ (86, Whitespace, "\n "),
+ (91, Name, "name"),
+ (95, Whitespace, "\n "),
+ (98, Punctuation, "}"),
+ (99, Whitespace, "\n"),
+ (100, Punctuation, "}"),
+ (101, Whitespace, "\n"),
+ ]
+ assert_tokens_equal(self, text, expected)
+
+ def test_variables(self):
+ text = """\
+ mutation testVar($int: Int, $myType: MyType,
+ $required: String!, $list: [Int!]!)
+ {
+ doSomenthing(int: $int, myType: $myType,
+ required: $required, list: $list)
+ {
+ response
+ }
+ }
+ """
+ expected = [
+ (0, Keyword, "mutation"),
+ (8, Whitespace, " "),
+ (9, Name.Function, "testVar"),
+ (16, Punctuation, "("),
+ (17, Name.Variable, "$int"),
+ (21, Punctuation, ":"),
+ (22, Whitespace, " "),
+ (23, Name.Builtin, "Int"),
+ (26, Punctuation, ","),
+ (27, Whitespace, " "),
+ (28, Name.Variable, "$myType"),
+ (35, Punctuation, ":"),
+ (36, Whitespace, " "),
+ (37, Name.Class, "MyType"),
+ (43, Punctuation, ","),
+ (44, Whitespace, "\n "),
+ (49, Name.Variable, "$required"),
+ (58, Punctuation, ":"),
+ (59, Whitespace, " "),
+ (60, Name.Builtin, "String"),
+ (66, Punctuation, "!"),
+ (67, Punctuation, ","),
+ (68, Whitespace, " "),
+ (69, Name.Variable, "$list"),
+ (74, Punctuation, ":"),
+ (75, Whitespace, " "),
+ (76, Punctuation, "["),
+ (77, Name.Builtin, "Int"),
+ (80, Punctuation, "!"),
+ (81, Punctuation, "]"),
+ (82, Punctuation, "!"),
+ (83, Punctuation, ")"),
+ (84, Whitespace, "\n"),
+ (85, Punctuation, "{"),
+ (86, Whitespace, "\n "),
+ (89, Name, "doSomenthing"),
+ (101, Punctuation, "("),
+ (102, Name, "int"),
+ (105, Punctuation, ":"),
+ (106, Whitespace, " "),
+ (107, Name.Variable, "$int"),
+ (111, Punctuation, ","),
+ (112, Whitespace, " "),
+ (113, Name, "myType"),
+ (119, Punctuation, ":"),
+ (120, Whitespace, " "),
+ (121, Name.Variable, "$myType"),
+ (128, Punctuation, ","),
+ (129, Whitespace, "\n "),
+ (136, Name, "required"),
+ (144, Punctuation, ":"),
+ (145, Whitespace, " "),
+ (146, Name.Variable, "$required"),
+ (155, Punctuation, ","),
+ (156, Whitespace, " "),
+ (157, Name, "list"),
+ (161, Punctuation, ":"),
+ (162, Whitespace, " "),
+ (163, Name.Variable, "$list"),
+ (168, Punctuation, ")"),
+ (169, Whitespace, "\n "),
+ (172, Punctuation, "{"),
+ (173, Whitespace, "\n "),
+ (178, Name, "response"),
+ (186, Whitespace, "\n "),
+ (189, Punctuation, "}"),
+ (190, Whitespace, "\n"),
+ (191, Punctuation, "}"),
+ (192, Whitespace, "\n"),
+ ]
+ assert_tokens_equal(self, text, expected)
+
+ def test_operation_definition_directives(self):
+ text = """\
+ query ($foo: Boolean = true, $bar: Boolean = false) {
+ field @skip(if: $foo) {
+ subfieldA
+ }
+ field @skip(if: $bar) {
+ subfieldB
+ }
+ }
+ """
+ expected = [
+ (0, Keyword, "query"),
+ (5, Whitespace, " "),
+ (6, Punctuation, "("),
+ (7, Name.Variable, "$foo"),
+ (11, Punctuation, ":"),
+ (12, Whitespace, " "),
+ (13, Name.Builtin, "Boolean"),
+ (20, Whitespace, " "),
+ (21, Punctuation, "="),
+ (22, Whitespace, " "),
+ (23, Name.Builtin, "true"),
+ (27, Punctuation, ","),
+ (28, Whitespace, " "),
+ (29, Name.Variable, "$bar"),
+ (33, Punctuation, ":"),
+ (34, Whitespace, " "),
+ (35, Name.Builtin, "Boolean"),
+ (42, Whitespace, " "),
+ (43, Punctuation, "="),
+ (44, Whitespace, " "),
+ (45, Name.Builtin, "false"),
+ (50, Punctuation, ")"),
+ (51, Whitespace, " "),
+ (52, Punctuation, "{"),
+ (53, Whitespace, "\n "),
+ (56, Name, "field"),
+ (61, Whitespace, " "),
+ (62, Name.Decorator, "@skip"),
+ (67, Punctuation, "("),
+ (68, Name, "if"),
+ (70, Punctuation, ":"),
+ (71, Whitespace, " "),
+ (72, Name.Variable, "$foo"),
+ (76, Punctuation, ")"),
+ (77, Whitespace, " "),
+ (78, Punctuation, "{"),
+ (79, Whitespace, "\n "),
+ (84, Name, "subfieldA"),
+ (93, Whitespace, "\n "),
+ (96, Punctuation, "}"),
+ (97, Whitespace, "\n "),
+ (100, Name, "field"),
+ (105, Whitespace, " "),
+ (106, Name.Decorator, "@skip"),
+ (111, Punctuation, "("),
+ (112, Name, "if"),
+ (114, Punctuation, ":"),
+ (115, Whitespace, " "),
+ (116, Name.Variable, "$bar"),
+ (120, Punctuation, ")"),
+ (121, Whitespace, " "),
+ (122, Punctuation, "{"),
+ (123, Whitespace, "\n "),
+ (128, Name, "subfieldB"),
+ (137, Whitespace, "\n "),
+ (140, Punctuation, "}"),
+ (141, Whitespace, "\n"),
+ (142, Punctuation, "}"),
+ (143, Whitespace, "\n"),
+ ]
+ assert_tokens_equal(self, text, expected)
+
+ def test_operation_definition_multi_directives(self):
+ text = """\
+ query ($foo: Boolean = true, $bar: Boolean = false) {
+ field @skip(if: $foo) @skip(if: $bar)
+ }
+ """
+ expected = [
+ (0, Keyword, "query"),
+ (5, Whitespace, " "),
+ (6, Punctuation, "("),
+ (7, Name.Variable, "$foo"),
+ (11, Punctuation, ":"),
+ (12, Whitespace, " "),
+ (13, Name.Builtin, "Boolean"),
+ (20, Whitespace, " "),
+ (21, Punctuation, "="),
+ (22, Whitespace, " "),
+ (23, Name.Builtin, "true"),
+ (27, Punctuation, ","),
+ (28, Whitespace, " "),
+ (29, Name.Variable, "$bar"),
+ (33, Punctuation, ":"),
+ (34, Whitespace, " "),
+ (35, Name.Builtin, "Boolean"),
+ (42, Whitespace, " "),
+ (43, Punctuation, "="),
+ (44, Whitespace, " "),
+ (45, Name.Builtin, "false"),
+ (50, Punctuation, ")"),
+ (51, Whitespace, " "),
+ (52, Punctuation, "{"),
+ (53, Whitespace, "\n "),
+ (56, Name, "field"),
+ (61, Whitespace, " "),
+ (62, Name.Decorator, "@skip"),
+ (67, Punctuation, "("),
+ (68, Name, "if"),
+ (70, Punctuation, ":"),
+ (71, Whitespace, " "),
+ (72, Name.Variable, "$foo"),
+ (76, Punctuation, ")"),
+ (77, Whitespace, " "),
+ (78, Name.Decorator, "@skip"),
+ (83, Punctuation, "("),
+ (84, Name, "if"),
+ (86, Punctuation, ":"),
+ (87, Whitespace, " "),
+ (88, Name.Variable, "$bar"),
+ (92, Punctuation, ")"),
+ (93, Whitespace, "\n"),
+ (94, Punctuation, "}"),
+ (95, Whitespace, "\n"),
+ ]
+ assert_tokens_equal(self, text, expected)
+
+ def test_fragment_spread(self):
+ text = """\
+ query withNestedFragments {
+ user(id: 4) {
+ friends(first: 10) {
+ ...friendFields
+ }
+ mutualFriends(first: 10) {
+ ...friendFields @skip(if: true)
+ }
+ }
+ }
+ """
+ expected = [
+ (0, Keyword, "query"),
+ (5, Whitespace, " "),
+ (6, Name.Function, "withNestedFragments"),
+ (25, Whitespace, " "),
+ (26, Punctuation, "{"),
+ (27, Whitespace, "\n "),
+ (30, Name, "user"),
+ (34, Punctuation, "("),
+ (35, Name, "id"),
+ (37, Punctuation, ":"),
+ (38, Whitespace, " "),
+ (39, Number.Integer, "4"),
+ (40, Punctuation, ")"),
+ (41, Whitespace, " "),
+ (42, Punctuation, "{"),
+ (43, Whitespace, "\n "),
+ (48, Name, "friends"),
+ (55, Punctuation, "("),
+ (56, Name, "first"),
+ (61, Punctuation, ":"),
+ (62, Whitespace, " "),
+ (63, Number.Integer, "10"),
+ (65, Punctuation, ")"),
+ (66, Whitespace, " "),
+ (67, Punctuation, "{"),
+ (68, Whitespace, "\n "),
+ (75, Punctuation, "..."),
+ (78, Name, "friendFields"),
+ (90, Whitespace, "\n "),
+ (95, Punctuation, "}"),
+ (96, Whitespace, "\n "),
+ (101, Name, "mutualFriends"),
+ (114, Punctuation, "("),
+ (115, Name, "first"),
+ (120, Punctuation, ":"),
+ (121, Whitespace, " "),
+ (122, Number.Integer, "10"),
+ (124, Punctuation, ")"),
+ (125, Whitespace, " "),
+ (126, Punctuation, "{"),
+ (127, Whitespace, "\n "),
+ (134, Punctuation, "..."),
+ (137, Name, "friendFields"),
+ (149, Whitespace, " "),
+ (150, Name.Decorator, "@skip"),
+ (155, Punctuation, "("),
+ (156, Name, "if"),
+ (158, Punctuation, ":"),
+ (159, Whitespace, " "),
+ (160, Name.Builtin, "true"),
+ (164, Punctuation, ")"),
+ (165, Whitespace, "\n "),
+ (170, Punctuation, "}"),
+ (171, Whitespace, "\n "),
+ (174, Punctuation, "}"),
+ (175, Whitespace, "\n"),
+ (176, Punctuation, "}"),
+ (177, Whitespace, "\n"),
+ ]
+ assert_tokens_equal(self, text, expected)
+
+ def test_inline_fragment(self):
+ text = """\
+ query inlineFragmentTyping {
+ profiles(handles: ["zuck", "cocacola"]) {
+ handle
+ ... on User {
+ friends {
+ count
+ }
+ }
+ ... on Page {
+ likers {
+ count
+ }
+ }
+ }
+ }
+ """
+ expected = [
+ (0, Keyword, "query"),
+ (5, Whitespace, " "),
+ (6, Name.Function, "inlineFragmentTyping"),
+ (26, Whitespace, " "),
+ (27, Punctuation, "{"),
+ (28, Whitespace, "\n "),
+ (31, Name, "profiles"),
+ (39, Punctuation, "("),
+ (40, Name, "handles"),
+ (47, Punctuation, ":"),
+ (48, Whitespace, " "),
+ (49, Punctuation, "["),
+ (50, String, '"'),
+ (51, String, "zuck"),
+ (55, String, '"'),
+ (56, Punctuation, ","),
+ (57, Whitespace, " "),
+ (58, String, '"'),
+ (59, String, "cocacola"),
+ (67, String, '"'),
+ (68, Punctuation, "]"),
+ (69, Punctuation, ")"),
+ (70, Whitespace, " "),
+ (71, Punctuation, "{"),
+ (72, Whitespace, "\n "),
+ (77, Name, "handle"),
+ (83, Whitespace, "\n "),
+ (88, Punctuation, "..."),
+ (91, Whitespace, " "),
+ (92, Keyword, "on"),
+ (94, Whitespace, " "),
+ (95, Name.Class, "User"),
+ (99, Whitespace, " "),
+ (100, Punctuation, "{"),
+ (101, Whitespace, "\n "),
+ (108, Name, "friends"),
+ (115, Whitespace, " "),
+ (116, Punctuation, "{"),
+ (117, Whitespace, "\n "),
+ (126, Name, "count"),
+ (131, Whitespace, "\n "),
+ (138, Punctuation, "}"),
+ (139, Whitespace, "\n "),
+ (144, Punctuation, "}"),
+ (145, Whitespace, "\n "),
+ (150, Punctuation, "..."),
+ (153, Whitespace, " "),
+ (154, Keyword, "on"),
+ (156, Whitespace, " "),
+ (157, Name.Class, "Page"),
+ (161, Whitespace, " "),
+ (162, Punctuation, "{"),
+ (163, Whitespace, "\n "),
+ (170, Name, "likers"),
+ (176, Whitespace, " "),
+ (177, Punctuation, "{"),
+ (178, Whitespace, "\n "),
+ (187, Name, "count"),
+ (192, Whitespace, "\n "),
+ (199, Punctuation, "}"),
+ (200, Whitespace, "\n "),
+ (205, Punctuation, "}"),
+ (206, Whitespace, "\n "),
+ (209, Punctuation, "}"),
+ (210, Whitespace, "\n"),
+ (211, Punctuation, "}"),
+ (212, Whitespace, "\n"),
+ ]
+ assert_tokens_equal(self, text, expected)
+
+ def test_input_value_nested_array(self):
+ text = """\
+ {
+ node(arg: [1, [2, 3]])
+ }
+ """
+ expected = [
+ (0, Punctuation, "{"),
+ (1, Whitespace, "\n "),
+ (4, Name, "node"),
+ (8, Punctuation, "("),
+ (9, Name, "arg"),
+ (12, Punctuation, ":"),
+ (13, Whitespace, " "),
+ (14, Punctuation, "["),
+ (15, Number.Integer, "1"),
+ (16, Punctuation, ","),
+ (17, Whitespace, " "),
+ (18, Punctuation, "["),
+ (19, Number.Integer, "2"),
+ (20, Punctuation, ","),
+ (21, Whitespace, " "),
+ (22, Number.Integer, "3"),
+ (23, Punctuation, "]"),
+ (24, Punctuation, "]"),
+ (25, Punctuation, ")"),
+ (26, Whitespace, "\n"),
+ (27, Punctuation, "}"),
+ (28, Whitespace, "\n"),
+ ]
+ assert_tokens_equal(self, text, expected)
+
+ def test_input_value_object(self):
+ text = """\
+ {
+ node(arg: {a: "a", b: "b"})
+ }
+ """
+ expected = [
+ (0, Punctuation, "{"),
+ (1, Whitespace, "\n "),
+ (4, Name, "node"),
+ (8, Punctuation, "("),
+ (9, Name, "arg"),
+ (12, Punctuation, ":"),
+ (13, Whitespace, " "),
+ (14, Punctuation, "{"),
+ (15, Name, "a"),
+ (16, Punctuation, ":"),
+ (17, Whitespace, " "),
+ (18, String, '"'),
+ (19, String, "a"),
+ (20, String, '"'),
+ (21, Punctuation, ","),
+ (22, Whitespace, " "),
+ (23, Name, "b"),
+ (24, Punctuation, ":"),
+ (25, Whitespace, " "),
+ (26, String, '"'),
+ (27, String, "b"),
+ (28, String, '"'),
+ (29, Punctuation, "}"),
+ (30, Punctuation, ")"),
+ (31, Whitespace, "\n"),
+ (32, Punctuation, "}"),
+ (33, Whitespace, "\n"),
+ ]
+ assert_tokens_equal(self, text, expected)
+
+ def test_input_nested_value_object(self):
+ text = """\
+ {
+ node(arg: {a: "a", b: {c: "c", d: {e: "e"}}})
+ }
+ """
+ expected = [
+ (0, Punctuation, "{"),
+ (1, Whitespace, "\n "),
+ (4, Name, "node"),
+ (8, Punctuation, "("),
+ (9, Name, "arg"),
+ (12, Punctuation, ":"),
+ (13, Whitespace, " "),
+ (14, Punctuation, "{"),
+ (15, Name, "a"),
+ (16, Punctuation, ":"),
+ (17, Whitespace, " "),
+ (18, String, '"'),
+ (19, String, "a"),
+ (20, String, '"'),
+ (21, Punctuation, ","),
+ (22, Whitespace, " "),
+ (23, Name, "b"),
+ (24, Punctuation, ":"),
+ (25, Whitespace, " "),
+ (26, Punctuation, "{"),
+ (27, Name, "c"),
+ (28, Punctuation, ":"),
+ (29, Whitespace, " "),
+ (30, String, '"'),
+ (31, String, "c"),
+ (32, String, '"'),
+ (33, Punctuation, ","),
+ (34, Whitespace, " "),
+ (35, Name, "d"),
+ (36, Punctuation, ":"),
+ (37, Whitespace, " "),
+ (38, Punctuation, "{"),
+ (39, Name, "e"),
+ (40, Punctuation, ":"),
+ (41, Whitespace, " "),
+ (42, String, '"'),
+ (43, String, "e"),
+ (44, String, '"'),
+ (45, Punctuation, "}"),
+ (46, Punctuation, "}"),
+ (47, Punctuation, "}"),
+ (48, Punctuation, ")"),
+ (49, Whitespace, "\n"),
+ (50, Punctuation, "}"),
+ (51, Whitespace, "\n"),
+ ]
+ assert_tokens_equal(self, text, expected)
+
+ def test_input_value_mixed(self):
+ text = """\
+ {
+ node1(arg: {a: [1, 2]})
+ node2(arg: [1, {a: "a"}])
+ }
+ """
+ expected = [
+ (0, Punctuation, "{"),
+ (1, Whitespace, "\n "),
+ (4, Name, "node1"),
+ (9, Punctuation, "("),
+ (10, Name, "arg"),
+ (13, Punctuation, ":"),
+ (14, Whitespace, " "),
+ (15, Punctuation, "{"),
+ (16, Name, "a"),
+ (17, Punctuation, ":"),
+ (18, Whitespace, " "),
+ (19, Punctuation, "["),
+ (20, Number.Integer, "1"),
+ (21, Punctuation, ","),
+ (22, Whitespace, " "),
+ (23, Number.Integer, "2"),
+ (24, Punctuation, "]"),
+ (25, Punctuation, "}"),
+ (26, Punctuation, ")"),
+ (27, Whitespace, "\n "),
+ (30, Name, "node2"),
+ (35, Punctuation, "("),
+ (36, Name, "arg"),
+ (39, Punctuation, ":"),
+ (40, Whitespace, " "),
+ (41, Punctuation, "["),
+ (42, Number.Integer, "1"),
+ (43, Punctuation, ","),
+ (44, Whitespace, " "),
+ (45, Punctuation, "{"),
+ (46, Name, "a"),
+ (47, Punctuation, ":"),
+ (48, Whitespace, " "),
+ (49, String, '"'),
+ (50, String, "a"),
+ (51, String, '"'),
+ (52, Punctuation, "}"),
+ (53, Punctuation, "]"),
+ (54, Punctuation, ")"),
+ (55, Whitespace, "\n"),
+ (56, Punctuation, "}"),
+ (57, Whitespace, "\n"),
+ ]
+ assert_tokens_equal(self, text, expected)