forked from STI/Astroport.ONE
71 lines
2.3 KiB
Python
71 lines
2.3 KiB
Python
|
from typing import Any
|
||
|
|
||
|
from .location import SourceLocation
|
||
|
|
||
|
__all__ = ["Source", "is_source"]
|
||
|
|
||
|
|
||
|
class Source:
|
||
|
"""A representation of source input to GraphQL."""
|
||
|
|
||
|
# allow custom attributes and weak references (not used internally)
|
||
|
__slots__ = "__weakref__", "__dict__", "body", "name", "location_offset"
|
||
|
|
||
|
def __init__(
|
||
|
self,
|
||
|
body: str,
|
||
|
name: str = "GraphQL request",
|
||
|
location_offset: SourceLocation = SourceLocation(1, 1),
|
||
|
) -> None:
|
||
|
"""Initialize source input.
|
||
|
|
||
|
The ``name`` and ``location_offset`` parameters are optional, but they are
|
||
|
useful for clients who store GraphQL documents in source files. For example,
|
||
|
if the GraphQL input starts at line 40 in a file named ``Foo.graphql``, it might
|
||
|
be useful for ``name`` to be ``"Foo.graphql"`` and location to be ``(40, 0)``.
|
||
|
|
||
|
The ``line`` and ``column`` attributes in ``location_offset`` are 1-indexed.
|
||
|
"""
|
||
|
self.body = body
|
||
|
self.name = name
|
||
|
if not isinstance(location_offset, SourceLocation):
|
||
|
location_offset = SourceLocation._make(location_offset)
|
||
|
if location_offset.line <= 0:
|
||
|
raise ValueError(
|
||
|
"line in location_offset is 1-indexed and must be positive."
|
||
|
)
|
||
|
if location_offset.column <= 0:
|
||
|
raise ValueError(
|
||
|
"column in location_offset is 1-indexed and must be positive."
|
||
|
)
|
||
|
self.location_offset = location_offset
|
||
|
|
||
|
def get_location(self, position: int) -> SourceLocation:
|
||
|
lines = self.body[:position].splitlines()
|
||
|
if lines:
|
||
|
line = len(lines)
|
||
|
column = len(lines[-1]) + 1
|
||
|
else:
|
||
|
line = 1
|
||
|
column = 1
|
||
|
return SourceLocation(line, column)
|
||
|
|
||
|
def __repr__(self) -> str:
|
||
|
return f"<{self.__class__.__name__} name={self.name!r}>"
|
||
|
|
||
|
def __eq__(self, other: Any) -> bool:
|
||
|
return (isinstance(other, Source) and other.body == self.body) or (
|
||
|
isinstance(other, str) and other == self.body
|
||
|
)
|
||
|
|
||
|
def __ne__(self, other: Any) -> bool:
|
||
|
return not self == other
|
||
|
|
||
|
|
||
|
def is_source(source: Any) -> bool:
|
||
|
"""Test if the given value is a Source object.
|
||
|
|
||
|
For internal use only.
|
||
|
"""
|
||
|
return isinstance(source, Source)
|