Skip to content

Commit 17ccd4a

Browse files
committed
print_location: Add special support for minified documents
Replicates graphql/graphql-js@d8c1dfd
1 parent 9edfcc2 commit 17ccd4a

File tree

4 files changed

+81
-16
lines changed

4 files changed

+81
-16
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ a query language for APIs created by Facebook.
1313
[![Code Style](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)
1414

1515
The current version 1.0.5 of GraphQL-core-next is up-to-date with GraphQL.js version
16-
14.3.1. All parts of the API are covered by an extensive test suite of currently 1880
16+
14.3.1. All parts of the API are covered by an extensive test suite of currently 1881
1717
unit tests.
1818

1919

graphql/language/print_location.py

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import re
2-
from typing import List, Optional, Tuple, cast
2+
from typing import Optional, Tuple, cast
33

44
from .ast import Location
55
from .location import SourceLocation, get_location
@@ -30,24 +30,40 @@ def print_source_location(source: Source, source_location: SourceLocation) -> st
3030

3131
column_offset = first_line_column_offset if source_location.line == 1 else 0
3232
column_num = source_location.column + column_offset
33+
location_str = f"{source.name}:{line_num}:{column_num}\n"
3334

3435
lines = _re_newline.split(body) # works a bit different from splitlines()
35-
len_lines = len(lines)
36-
37-
def get_line(index: int) -> Optional[str]:
38-
return lines[index] if 0 <= index < len_lines else None
39-
40-
return f"{source.name}:{line_num}:{column_num}\n" + print_prefixed_lines(
41-
[
42-
(f"{line_num - 1}", get_line(line_index - 1)),
43-
(f"{line_num}", get_line(line_index)),
44-
("", " " * (column_num - 1) + "^"),
45-
(f"{line_num + 1}", get_line(line_index + 1)),
46-
]
36+
location_line = lines[line_index]
37+
38+
# Special case for minified documents
39+
if len(location_line) > 120:
40+
subline_index, subline_column_num = divmod(column_num, 80)
41+
sublines = [location_line[i : i + 80] for i in range(0, len(location_line), 80)]
42+
43+
return location_str + print_prefixed_lines(
44+
(str(line_num), sublines[0]),
45+
*[("", subline) for subline in sublines[1 : subline_index + 1]],
46+
(" ", " " * (subline_column_num - 1) + "^"),
47+
(
48+
"",
49+
sublines[subline_index + 1]
50+
if subline_index < len(sublines) - 1
51+
else None,
52+
),
53+
)
54+
55+
return location_str + print_prefixed_lines(
56+
(f"{line_num - 1}", lines[line_index - 1] if line_index > 0 else None),
57+
(f"{line_num}", location_line),
58+
("", " " * (column_num - 1) + "^"),
59+
(
60+
f"{line_num + 1}",
61+
lines[line_index + 1] if line_index < len(lines) - 1 else None,
62+
),
4763
)
4864

4965

50-
def print_prefixed_lines(lines: List[Tuple[str, Optional[str]]]) -> str:
66+
def print_prefixed_lines(*lines: Tuple[str, Optional[str]]) -> str:
5167
"""Print lines specified like this: ("prefix", "string")"""
5268
existing_lines = [
5369
cast(Tuple[str, str], line) for line in lines if line[1] is not None

tests/error/test_print_location.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,55 @@
33

44

55
def describe_print_location():
6+
def prints_minified_documents():
7+
minified_source = Source(
8+
"query SomeMiniFiedQueryWithErrorInside("
9+
"$foo:String!=FIRST_ERROR_HERE$bar:String)"
10+
"{someField(foo:$foo bar:$bar baz:SECOND_ERROR_HERE)"
11+
"{fieldA fieldB{fieldC fieldD...on THIRD_ERROR_HERE}}}"
12+
)
13+
14+
first_location = print_source_location(
15+
minified_source,
16+
SourceLocation(1, minified_source.body.index("FIRST_ERROR_HERE") + 1),
17+
)
18+
assert first_location + "\n" == dedent(
19+
"""
20+
GraphQL request:1:53
21+
1 | query SomeMiniFiedQueryWithErrorInside($foo:String!=FIRST_ERROR_HERE$bar:String)
22+
| ^
23+
| {someField(foo:$foo bar:$bar baz:SECOND_ERROR_HERE){fieldA fieldB{fieldC fieldD.
24+
""" # noqa: E501
25+
)
26+
27+
second_location = print_source_location(
28+
minified_source,
29+
SourceLocation(1, minified_source.body.index("SECOND_ERROR_HERE") + 1),
30+
)
31+
assert second_location + "\n" == dedent(
32+
"""
33+
GraphQL request:1:114
34+
1 | query SomeMiniFiedQueryWithErrorInside($foo:String!=FIRST_ERROR_HERE$bar:String)
35+
| {someField(foo:$foo bar:$bar baz:SECOND_ERROR_HERE){fieldA fieldB{fieldC fieldD.
36+
| ^
37+
| ..on THIRD_ERROR_HERE}}}
38+
""" # noqa: E501
39+
)
40+
41+
third_location = print_source_location(
42+
minified_source,
43+
SourceLocation(1, minified_source.body.index("THIRD_ERROR_HERE") + 1),
44+
)
45+
assert third_location + "\n" == dedent(
46+
"""
47+
GraphQL request:1:166
48+
1 | query SomeMiniFiedQueryWithErrorInside($foo:String!=FIRST_ERROR_HERE$bar:String)
49+
| {someField(foo:$foo bar:$bar baz:SECOND_ERROR_HERE){fieldA fieldB{fieldC fieldD.
50+
| ..on THIRD_ERROR_HERE}}}
51+
| ^
52+
""" # noqa: E501
53+
)
54+
655
def prints_single_digit_line_number_with_no_padding():
756
result = print_source_location(
857
Source("*", "Test", SourceLocation(9, 1)), SourceLocation(1, 1)

tests/language/test_parser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def parse_provides_useful_error_when_using_source():
9494
assert str(error) + "\n" == dedent(
9595
"""
9696
Syntax Error: Expected {, found <EOF>
97-
97+
9898
MyQuery.graphql:1:6
9999
1 | query
100100
| ^

0 commit comments

Comments
 (0)