Skip to content

Commit 3c361ce

Browse files
committed
cleanup the introspection API
add GQLDocument.toFullSchemaGQLDocument and GQLDocument.mergeExtensions
1 parent b141b76 commit 3c361ce

File tree

59 files changed

+8117
-2016
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+8117
-2016
lines changed

build-logic/src/main/kotlin/Common.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmTest
1010
fun Project.commonSetup() {
1111
pluginManager.withPlugin("org.jetbrains.kotlin.jvm") {
1212
tasks.register("ft") {
13-
if (this@commonSetup.name != "apollo-gradle-plugin") {
13+
if (this@commonSetup.name !in setOf("apollo-gradle-plugin", "intellij-plugin")) {
1414
dependsOn("test")
1515
}
1616
}
@@ -37,6 +37,8 @@ private fun Project.configureTestAggregation() {
3737
attribute(USAGE_ATTRIBUTE, objects.named(Usage::class.java, "apolloTestAggregation"))
3838
}
3939
}
40+
// Hide this from the 'assemble' task
41+
configuration.setVisible(false)
4042

4143
tasks.withType(AbstractTestTask::class.java).configureEach {
4244
configuration.getOutgoing().artifact(

docs/source/advanced/apollo-ast.mdx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ val graphQLText = """
4242
}
4343
""".trimIndent()
4444

45-
val parseResult = Buffer().writeUtf8(graphQLText).parseAsGQLDocument()
45+
val parseResult = graphQLText.parseAsGQLDocument()
4646
```
4747

4848
This method returns a `GQLResult<GQLDocument>`, which contains the document and/or parsing issues, each of which can have a severity of either `WARNING` or `ERROR`. Because there can be warnings, it is possible to have both a valid document and issues at the same time.
@@ -111,7 +111,7 @@ val schemaText = """
111111
}
112112
""".trimIndent()
113113

114-
val schemaGQLDocument = Buffer().writeUtf8(schemaText).parseAsGQLDocument().getOrThrow()
114+
val schemaGQLDocument = schemaText.parseAsGQLDocument().getOrThrow()
115115
val schemaResult = schemaGQLDocument.validateAsSchema()
116116
println(schemaResult.issues.map { it.severity.name + ": " + it.message })
117117
```
@@ -146,9 +146,6 @@ println(queryGqlDocument.toUtf8())
146146

147147
// Output to a File
148148
queryGqlDocument.toUtf8(file)
149-
150-
// Output to an Okio BufferedSink
151-
queryGqlDocument.toUtf8(sink)
152149
```
153150

154151
## Transforming an AST

docs/source/migration/4.0.mdx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -197,15 +197,17 @@ The normalized cache must be configured before the auto persisted queries, confi
197197

198198
## apollo-ast
199199

200-
The AST classes (`GQLNode` and subclasses) as well as `Introspection` classes are not data classes anymore (see https://github.com/apollographql/apollo-kotlin/pull/4704/).
200+
The AST classes (`GQLNode` and subclasses) as well as `Introspection` classes are not data classes anymore (see https://github.com/apollographql/apollo-kotlin/pull/4704/). The class hierarchy has been tweaked so that `GQLNamed`, `GQLDescribed` and `GQLHasDirectives` are more consistently inherited from.
201201

202-
`GQLSelectionSet` and `GQLArguments` are deprecated and removed from `GQLField`, `GQLInlineFragment` and other constructors. Use `.selections` directly
202+
`GQLSelectionSet` and `GQLArguments` are deprecated and removed from `GQLField`, `GQLInlineFragment`. Use `.selections` directly
203203

204-
`GQLInlineFragment.typeCondition` is now nullable to account for inline fragments who inherit their type condition
204+
`GQLInlineFragment.typeCondition` is now nullable to account for inline fragments who inherit their type condition.
205+
206+
`SourceLocation.position` is renamed `SourceLocation.column` and is now 1-indexed. `GQLNode.sourceLocation` is now nullable to account for the cases where the nodes are constructed programmatically.
207+
208+
It is not possible to create a `Schema` from a File or String directly anymore. Instead, create a `GQLDocument` first and convert it to a schema with `toSchema()`.
205209

206-
`SourceLocation.position` is renamed `SourceLocation.column` and is now 1-indexed
207210

208-
`GQLNode.sourceLocation` is now nullable
209211

210212
## Gradle configuration
211213

libraries/apollo-ast/api/apollo-ast.api

Lines changed: 28 additions & 523 deletions
Large diffs are not rendered by default.

libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo3/ast/SDLWriter.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package com.apollographql.apollo3.ast
22

3+
import com.apollographql.apollo3.annotations.ApolloInternal
34
import okio.BufferedSink
45
import okio.Closeable
56

67
/**
78
* A [SDLWriter] writes utf8 text to the given sink and supports [indent]/[unindent]
89
*/
10+
@ApolloInternal
911
open class SDLWriter(
1012
private val sink: BufferedSink,
1113
private val indent: String,

libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo3/ast/Schema.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class Schema internal constructor(
4747

4848
fun toGQLDocument(): GQLDocument = GQLDocument(
4949
definitions = definitions,
50-
filePath = null
50+
sourceLocation = null
5151
)
5252

5353
/**

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class SourceLocation(
3131
get() = column - 1
3232

3333
override fun toString(): String {
34-
return "($line:$column)"
34+
return pretty()
3535
}
3636

3737
fun pretty(): String = "$filePath: ($line, $column)"

libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo3/ast/api.kt

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import com.apollographql.apollo3.ast.internal.LexerException
1111
import com.apollographql.apollo3.ast.internal.Parser
1212
import com.apollographql.apollo3.ast.internal.ParserException
1313
import com.apollographql.apollo3.ast.internal.validateSchema
14+
import com.apollographql.apollo3.ast.introspection.toGQLDocument
15+
import com.apollographql.apollo3.ast.introspection.toIntrospectionSchema
1416
import okio.Buffer
1517
import okio.BufferedSource
1618
import okio.Path
@@ -19,16 +21,6 @@ import okio.use
1921
import kotlin.jvm.JvmMultifileClass
2022
import kotlin.jvm.JvmName
2123

22-
/**
23-
* Parses the source to a [Schema], throwing on parsing or validation errors.
24-
*
25-
* See [parseAsGQLDocument] and [validateAsSchema] for more granular error reporting
26-
*/
27-
@ApolloExperimental
28-
fun BufferedSource.toSchema(filePath: String? = null): Schema = parseAsGQLDocument(filePath).getOrThrow().validateAsSchema().getOrThrow()
29-
30-
fun String.toSchema(): Schema = parseAsGQLDocument().getOrThrow().validateAsSchema().getOrThrow()
31-
3224
/**
3325
* Parses the source to a List<[GQLDefinition]>, throwing on parsing or validation errors.
3426
*
@@ -145,6 +137,10 @@ fun String.parseAsGQLDocument(options: ParserOptions = ParserOptions.Default): G
145137
}
146138
}
147139

140+
fun String.toGQLDocument(options: ParserOptions = ParserOptions.Default): GQLDocument {
141+
return parseAsGQLDocument(options).getOrThrow()
142+
}
143+
148144
fun String.parseAsGQLValue(options: ParserOptions = ParserOptions.Default): GQLResult<GQLValue> {
149145
@Suppress("DEPRECATION")
150146
return if (options.useAntlr) {
@@ -154,6 +150,10 @@ fun String.parseAsGQLValue(options: ParserOptions = ParserOptions.Default): GQLR
154150
}
155151
}
156152

153+
fun String.toGQLValue(options: ParserOptions = ParserOptions.Default): GQLValue {
154+
return parseAsGQLValue(options).getOrThrow()
155+
}
156+
157157
fun String.parseAsGQLType(options: ParserOptions = ParserOptions.Default): GQLResult<GQLType> {
158158
@Suppress("DEPRECATION")
159159
return if (options.useAntlr) {
@@ -163,12 +163,20 @@ fun String.parseAsGQLType(options: ParserOptions = ParserOptions.Default): GQLRe
163163
}
164164
}
165165

166+
fun String.toGQLType(options: ParserOptions = ParserOptions.Default): GQLType {
167+
return parseAsGQLType(options).getOrThrow()
168+
}
169+
166170
internal fun String.parseAsGQLNullability(options: ParserOptions = ParserOptions.Default): GQLResult<GQLNullability> {
167171
@Suppress("DEPRECATION")
168-
check (!options.useAntlr)
172+
check(!options.useAntlr)
169173
return parseInternal(null, options) { parseNullability() ?: error("No nullability") }
170174
}
171175

176+
fun String.toGQLNullability(options: ParserOptions = ParserOptions.Default): GQLNullability {
177+
return parseAsGQLNullability(options).getOrThrow()
178+
}
179+
172180
fun String.parseAsGQLSelections(options: ParserOptions = ParserOptions.Default): GQLResult<List<GQLSelection>> {
173181
@Suppress("DEPRECATION")
174182
return if (options.useAntlr) {
@@ -178,10 +186,22 @@ fun String.parseAsGQLSelections(options: ParserOptions = ParserOptions.Default):
178186
}
179187
}
180188

189+
fun String.toGQLSelections(options: ParserOptions = ParserOptions.Default): List<GQLSelection> {
190+
return parseAsGQLSelections(options).getOrThrow()
191+
}
192+
181193
fun Path.parseAsGQLDocument(options: ParserOptions = ParserOptions.Default): GQLResult<GQLDocument> {
182194
return HOST_FILESYSTEM.source(this).buffer().parseAsGQLDocument(filePath = toString(), options = options)
183195
}
184196

197+
fun Path.toGQLDocument(options: ParserOptions = ParserOptions.Default, allowJson: Boolean = false): GQLDocument {
198+
return if (allowJson && name.endsWith(".json")) {
199+
toIntrospectionSchema().toGQLDocument()
200+
} else {
201+
parseAsGQLDocument(options).getOrThrow()
202+
}
203+
}
204+
185205
/**
186206
* Parses the source to a [GQLDocument], validating the syntax but not the contents of the document.
187207
*

libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo3/ast/gql.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ sealed interface GQLNode {
4646
fun copyWithNewChildrenInternal(container: NodeContainer): GQLNode
4747
}
4848

49+
@ApolloExperimental
4950
sealed interface TransformResult {
5051
object Delete : TransformResult
5152
object Continue : TransformResult
@@ -57,10 +58,12 @@ sealed interface TransformResult {
5758
class Replace(val newNode: GQLNode) : TransformResult
5859
}
5960

61+
@ApolloExperimental
6062
fun interface NodeTransformer {
6163
fun transform(node: GQLNode): TransformResult
6264
}
6365

66+
@ApolloExperimental
6467
fun GQLNode.transform(transformer: NodeTransformer): GQLNode? {
6568
return when (val result = transformer.transform(this)) {
6669
is TransformResult.Delete -> null
@@ -117,7 +120,7 @@ interface GQLHasDirectives {
117120

118121
sealed interface GQLDefinition : GQLNode
119122
sealed interface GQLExecutableDefinition : GQLDefinition
120-
sealed interface GQLTypeSystemExtension : GQLNode
123+
sealed interface GQLTypeSystemExtension : GQLDefinition
121124
sealed interface GQLTypeExtension : GQLTypeSystemExtension, GQLNamed
122125

123126
sealed class GQLSelection : GQLNode
@@ -132,6 +135,8 @@ class GQLDocument(
132135
val definitions: List<GQLDefinition>,
133136
override val sourceLocation: SourceLocation?,
134137
) : GQLNode {
138+
@Deprecated("Use sourceLocation primary constructor", level = DeprecationLevel.ERROR)
139+
@ApolloDeprecatedSince(ApolloDeprecatedSince.Version.v4_0_0)
135140
constructor(definitions: List<GQLDefinition>, filePath: String?) : this(definitions, SourceLocation.forPath(filePath))
136141

137142
override val children = definitions

libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo3/ast/gqldirective.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,19 @@ fun List<GQLDirective>.findDeprecationReason() = firstOrNull { it.name == "depre
1616
?: "No longer supported"
1717
}
1818

19+
fun List<GQLDirective>.findSpecifiedBy() = firstOrNull { it.name == "specifiedBy" }
20+
?.let { directive ->
21+
directive.arguments
22+
.firstOrNull { it.name == "url" }
23+
?.value
24+
?.let { value ->
25+
if (value !is GQLStringValue) {
26+
throw ConversionException("url must be a string", directive.sourceLocation)
27+
}
28+
value.value
29+
}
30+
}
31+
1932
@ApolloInternal
2033
fun List<GQLDirective>.findOptInFeature(schema: Schema): String? = filter { schema.originalDirectiveName(it.name) == Schema.REQUIRES_OPT_IN }
2134
.map {

libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo3/ast/gqldocument.kt

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ package com.apollographql.apollo3.ast
22

33
import com.apollographql.apollo3.annotations.ApolloDeprecatedSince
44
import com.apollographql.apollo3.annotations.ApolloExperimental
5+
import com.apollographql.apollo3.ast.internal.ExtensionsMerger
56
import com.apollographql.apollo3.ast.internal.apollo_v0_1_definitionsStr
67
import com.apollographql.apollo3.ast.internal.apollo_v0_2_definitionsStr
78
import com.apollographql.apollo3.ast.internal.builtinsDefinitionsStr
9+
import com.apollographql.apollo3.ast.internal.ensureSchemaDefinition
810
import com.apollographql.apollo3.ast.internal.linkDefinitionsStr
911
import okio.Buffer
1012

@@ -22,7 +24,26 @@ fun GQLDocument.withBuiltinDefinitions(): GQLDocument {
2224
return withDefinitions(builtinDefinitions())
2325
}
2426

25-
@Deprecated("Use GQLDocument.toSDL() to write a GQLDocument without the scalar directives")
27+
/**
28+
* Returns a "full schema" document. Full schema documents are for use by clients and other tools that need
29+
* to know what features are supported by a given server. They include builtin directives and merge all type
30+
* extensions
31+
*/
32+
@ApolloExperimental
33+
fun GQLDocument.toFullSchemaGQLDocument(): GQLDocument {
34+
return ensureSchemaDefinition()
35+
.withDefinitions(builtinDefinitions())
36+
.mergeExtensions()
37+
}
38+
39+
fun GQLDocument.toSchema(): Schema = validateAsSchema().getOrThrow()
40+
41+
@ApolloExperimental
42+
fun GQLDocument.mergeExtensions(): GQLDocument {
43+
return GQLDocument(ExtensionsMerger(definitions).merge().getOrThrow(), sourceLocation = null)
44+
}
45+
46+
@Deprecated("Use GQLDocument.toSDL() to write a GQLDocument")
2647
@ApolloDeprecatedSince(ApolloDeprecatedSince.Version.v4_0_0)
2748
fun GQLDocument.withoutBuiltinDefinitions(): GQLDocument {
2849
return withoutDefinitions(builtinDefinitions())
@@ -123,6 +144,7 @@ private fun GQLDocument.withDefinitions(definitions: List<GQLDefinition>): GQLDo
123144
)
124145
}
125146

147+
126148
/**
127149
* Outputs a schema document to SDL. For executable documents, use toUtf8()
128150
*

libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo3/ast/gqlnode.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22
@file:JvmName("GqlnodeKt")
33
package com.apollographql.apollo3.ast
44

5+
import com.apollographql.apollo3.annotations.ApolloExperimental
56
import okio.Buffer
67
import okio.BufferedSink
78
import kotlin.jvm.JvmMultifileClass
89
import kotlin.jvm.JvmName
910

11+
@ApolloExperimental
1012
fun GQLNode.toUtf8(sink: BufferedSink, indent: String = " ") {
1113
val writer = SDLWriter(sink, indent)
1214
writer.write(this)

0 commit comments

Comments
 (0)