Skip to content

Commit

Permalink
Apollo AST: add start/end instead of endColumn/endLine (#5103)
Browse files Browse the repository at this point in the history
* replace endLine/endColumn by start/end

* update API dump

* Update libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo3/ast/SourceLocation.kt

Co-authored-by: Benoit Lubek <[email protected]>

---------

Co-authored-by: Benoit Lubek <[email protected]>
  • Loading branch information
martinbonnin and BoD authored Jul 18, 2023
1 parent 4babca1 commit 01a097b
Show file tree
Hide file tree
Showing 13 changed files with 231 additions and 130 deletions.
4 changes: 2 additions & 2 deletions libraries/apollo-ast/api/apollo-ast.api
Original file line number Diff line number Diff line change
Expand Up @@ -910,11 +910,11 @@ public final class com/apollographql/apollo3/ast/SourceLocation {
public static final field Companion Lcom/apollographql/apollo3/ast/SourceLocation$Companion;
public fun <init> (IIIILjava/lang/String;)V
public final fun getColumn ()I
public final fun getEndColumn ()I
public final fun getEndLine ()I
public final fun getEnd ()I
public final fun getFilePath ()Ljava/lang/String;
public final fun getLine ()I
public final fun getPosition ()I
public final fun getStart ()I
public final fun pretty ()Ljava/lang/String;
public fun toString ()Ljava/lang/String;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,26 @@ package com.apollographql.apollo3.ast
import com.apollographql.apollo3.annotations.ApolloDeprecatedSince

/**
* @param start the offset where the symbol starts, inclusive, starting at 0
* Note that because the parser works on UTF16 Strings, the offset is in terms of UTF16 chars and not unicode Chars
*
* @param end the offset where the symbol ends, exclusive
* Because [end] is exclusive, you can use str.substring(start, end) to get the symbol text
* Note that because the parser works on UTF16 Strings, the offset is in terms of UTF16 chars and not unicode Chars
*
* @param line the line where the symbol starts, starting at 1
*
* @param column the column where the symbol starts, starting at 1
* Note that because the parser works on UTF16 Strings, the column is in terms of UTF16 chars and not unicode Chars
*
* @param endLine the line where the symbol ends, inclusive, starting at 1
*
* @param endColumn the column where the symbol ends, inclusive, starting at 1
* *
* @param filePath The path to the document containing the node
* Might be null if the document origin is not known
* Might be null if the document origin is not known (parsing from a String for an example)
*/
class SourceLocation(
val start: Int,
val end: Int,
val line: Int,
val column: Int,
val endLine: Int,
val endColumn: Int,
val filePath: String?
) {
@ApolloDeprecatedSince(ApolloDeprecatedSince.Version.v4_0_0)
Expand All @@ -35,7 +39,22 @@ class SourceLocation(
companion object {
@ApolloDeprecatedSince(ApolloDeprecatedSince.Version.v4_0_0)
@Deprecated("SourceLocation is now nullable and this is replaced by null", ReplaceWith("null"), level = DeprecationLevel.ERROR)
val UNKNOWN = SourceLocation(-1, -1, -1, -1, null)
val UNKNOWN = SourceLocation.forPath(null)

/**
* Constructs a [SourceLocation] that only contains a filePath for the moments when we're constructing nodes programmatically
* but still want to carry around the path of the original nodes for debugging purposes.
* TODO: I'm not sure how much this is helping vs confusing. We might want to remove that and just set a null sourceLocation in those cases
*/
internal fun forPath(filePath: String?): SourceLocation {
return SourceLocation(
start = 0,
end = 1,
line = -1,
column = -1,
filePath = filePath
)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,57 @@ fun BufferedSource.toSchema(filePath: String? = null): Schema = parseAsGQLDocume
* See [parseAsGQLDocument] and [validateAsExecutable] for more granular error reporting
*/
@ApolloExperimental
fun BufferedSource.toExecutableDefinitions(schema: Schema, filePath: String? = null, fieldsOnDisjointTypesMustMerge: Boolean = true): List<GQLDefinition> = parseAsGQLDocument(filePath)
fun BufferedSource.toExecutableDefinitions(
schema: Schema,
filePath: String? = null,
fieldsOnDisjointTypesMustMerge: Boolean = true,
): List<GQLDefinition> = parseAsGQLDocument(filePath)
.getOrThrow()
.validateAsExecutable(schema, fieldsOnDisjointTypesMustMerge)
.getOrThrow()

private fun <T: Any> BufferedSource.parseInternal(filePath: String?, withSourceLocation: Boolean, block: Parser.() -> T): GQLResult<T> {
private fun <T : Any> BufferedSource.parseInternal(filePath: String?, withSourceLocation: Boolean, block: Parser.() -> T): GQLResult<T> {
return try {
GQLResult(Parser(this.use { it.readUtf8() }, withSourceLocation, filePath).block(), emptyList())
} catch (e: ParserException) {
GQLResult(null, listOf(Issue.ParsingError(e.message, SourceLocation(e.token.line, e.token.column, -1, -1, filePath))))
GQLResult(
null,
listOf(
Issue.ParsingError(
e.message,
SourceLocation(
start = e.token.start,
end = e.token.end,
line = e.token.line,
column = e.token.column,
filePath = filePath
)
)
)
)
} catch (e: LexerException) {
GQLResult(null, listOf(Issue.ParsingError(e.message, SourceLocation(e.line, e.column, -1, -1, filePath))))
GQLResult(
null,
listOf(
Issue.ParsingError(
e.message,
SourceLocation(
start = e.pos,
end = e.pos + 1,
line = e.line,
column = e.column,
filePath = filePath
)
)
)
)
}
}

class ParserOptions(
val useAntlr: Boolean = false,
val allowEmptyDocuments: Boolean = true,
val withSourceLocation: Boolean = true
val withSourceLocation: Boolean = true,
) {
companion object {
val Default = ParserOptions()
Expand Down Expand Up @@ -96,7 +128,7 @@ fun BufferedSource.parseAsGQLValue(filePath: String? = null, options: ParserOpti
* Closes [BufferedSource]
*/
@ApolloExperimental
fun BufferedSource.parseAsGQLType(filePath: String? = null, options: ParserOptions = ParserOptions.Default): GQLResult<GQLType> {
fun BufferedSource.parseAsGQLType(filePath: String? = null, options: ParserOptions = ParserOptions.Default): GQLResult<GQLType> {
return if (options.useAntlr) {
parseTypeWithAntlr(this, filePath)
} else {
Expand All @@ -110,7 +142,10 @@ fun BufferedSource.parseAsGQLType(filePath: String? = null, options: ParserOptio
* Closes [BufferedSource]
*/
@ApolloExperimental
fun BufferedSource.parseAsGQLSelections(filePath: String? = null, options: ParserOptions = ParserOptions.Default): GQLResult<List<GQLSelection>> {
fun BufferedSource.parseAsGQLSelections(
filePath: String? = null,
options: ParserOptions = ParserOptions.Default,
): GQLResult<List<GQLSelection>> {
return if (options.useAntlr) {
parseSelectionsWithAntlr(this, filePath)
} else {
Expand Down Expand Up @@ -164,7 +199,7 @@ fun GQLDocument.validateAsExecutable(schema: Schema, fieldsOnDisjointTypesMustMe
fun GQLFragmentDefinition.inferVariables(
schema: Schema,
fragments: Map<String, GQLFragmentDefinition>,
fieldsOnDisjointTypesMustMerge: Boolean
fieldsOnDisjointTypesMustMerge: Boolean,
) = ExecutableValidationScope(schema, fragments, fieldsOnDisjointTypesMustMerge).inferFragmentVariables(this)


Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ class GQLDocument(
val definitions: List<GQLDefinition>,
override val sourceLocation: SourceLocation?,
) : GQLNode {
constructor(definitions: List<GQLDefinition>, filePath: String?): this(definitions, SourceLocation(0, 0, -1, -1, filePath))
constructor(definitions: List<GQLDefinition>, filePath: String?): this(definitions, SourceLocation.forPath(filePath))

override val children = definitions

Expand Down
Loading

0 comments on commit 01a097b

Please sign in to comment.