Skip to content

Commit

Permalink
[apollo-ast] Turn into a mpp module and move jmh benchmark to an inte…
Browse files Browse the repository at this point in the history
…gration test (#5072)

* turn apollo-ast into a mpp module and move jmh benchmark to an integration test

* stick with okio 3.2.0 until we bump our Kotlin requirements

* Update libraries/apollo-ast/src/appleMain/kotlin/com/apollographql/apollo3/ast/antlr.apple.kt

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

* Update libraries/apollo-ast/src/jsMain/kotlin/com/apollographql/apollo3/ast/antlr.js.kt

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

* Update libraries/apollo-ast/src/linuxMain/kotlin/com/apollographql/apollo3/ast/antlr.linux.kt

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

---------

Co-authored-by: Benoit Lubek <[email protected]>
  • Loading branch information
martinbonnin and BoD authored Jul 10, 2023
1 parent 6ef957f commit 18963c3
Show file tree
Hide file tree
Showing 88 changed files with 750 additions and 442 deletions.
18 changes: 0 additions & 18 deletions build-logic/src/main/kotlin/Mpp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -116,24 +116,6 @@ fun Project.configureMpp(
}
}

fun Project.okio(): String {
val okioVersion = when (getKotlinPluginVersion()) {
"1.6.10" -> "3.0.0"
else -> "3.2.0"
}

return "com.squareup.okio:okio:$okioVersion"
}

fun Project.okioNodeJs(): String {
val okioVersion = when (getKotlinPluginVersion()) {
"1.6.10" -> "3.0.0"
else -> "3.2.0"
}

return "com.squareup.okio:okio-nodefilesystem:$okioVersion"
}

private fun KotlinMultiplatformExtension.createAndConfigureAppleTargets(presetNames: Collection<String>) {
if (presetNames.isEmpty()) {
return
Expand Down
5 changes: 4 additions & 1 deletion gradle/libraries.toml
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,10 @@ okhttp-logging = { group = "com.squareup.okhttp3", name = "logging-interceptor",
okhttp-mockwebserver = { group = "com.squareup.okhttp3", name = "mockwebserver", version.ref = "okhttp" }
okhttp-tls = { group = "com.squareup.okhttp3", name = "okhttp-tls", version.ref = "okhttp" }
moshi = { group = "com.squareup.moshi", name = "moshi", version = "1.14.0" }
okio = "com.squareup.okio:okio-jvm:3.3.0"
# okio is pinned to 3.2.0 to stay compatible with Kotlin 1.5.
# bump it whenever we bump Kotlin
okio = "com.squareup.okio:okio:3.2.0"
okio-nodefilesystem = "com.squareup.okio:okio-nodefilesystem:3.2.0"
poet-java = { group = "com.squareup", name = "javapoet", version.ref = "javaPoet" }
poet-kotlin = { group = "com.squareup", name = "kotlinpoet", version = "1.12.0" }
rx-java2 = { group = "io.reactivex.rxjava2", name = "rxjava", version.ref = "rx-java2" }
Expand Down
2 changes: 1 addition & 1 deletion libraries/apollo-api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ kotlin {
sourceSets {
findByName("commonMain")?.apply {
dependencies {
api(okio())
api(golatac.lib("okio"))
api(golatac.lib("uuid"))
api(project(":apollo-annotations"))
}
Expand Down
2 changes: 1 addition & 1 deletion libraries/apollo-ast/api/apollo-ast.api
Original file line number Diff line number Diff line change
Expand Up @@ -835,7 +835,7 @@ public final class com/apollographql/apollo3/ast/ParserOptions {
public fun <init> ()V
public fun <init> (ZZZ)V
public synthetic fun <init> (ZZZILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun getAllowEmpty ()Z
public final fun getAllowEmptyDocuments ()Z
public final fun getUseAntlr ()Z
public final fun getWithSourceLocation ()Z
}
Expand Down
62 changes: 40 additions & 22 deletions libraries/apollo-ast/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,50 +1,68 @@
plugins {
antlr
id("org.jetbrains.kotlin.jvm")
id("org.jetbrains.kotlin.multiplatform")
id("apollo.library")
id("org.jetbrains.kotlin.plugin.serialization")
id("org.jetbrains.kotlinx.benchmark")
}

apolloLibrary {
javaModuleName("com.apollographql.apollo3.ast")
mpp {}
}

sourceSets.create("jmh")
kotlin {
jvm {
withJava()
}
sourceSets {
getByName("commonMain") {
dependencies {
api(golatac.lib("okio"))
api(project(":apollo-annotations"))
implementation(golatac.lib("kotlinx.serialization.json"))
}
}

benchmark {
targets {
register("jmh")
getByName("jsMain") {
dependencies {
implementation(golatac.lib("okio.nodefilesystem"))
}
}
getByName("jvmMain") {
dependencies {
implementation(golatac.lib("antlr.runtime"))
}
}
}
}

dependencies {
antlr(golatac.lib("antlr"))
implementation(golatac.lib("antlr.runtime"))
api(okio())
api(project(":apollo-annotations"))

implementation(golatac.lib("kotlinx.serialization.json"))

testImplementation(golatac.lib("kotlin.test.junit"))

add("jmhImplementation", golatac.lib("kotlinx.benchmark.runtime"))
add("jmhImplementation", sourceSets.main.get().output + sourceSets.main.get().runtimeClasspath)
}

// Only expose the antlr runtime dependency
// See https://github.com/gradle/gradle/issues/820#issuecomment-288838412
configurations[JavaPlugin.API_CONFIGURATION_NAME].let { apiConfiguration ->
apiConfiguration.setExtendsFrom(apiConfiguration.extendsFrom.filter { it.name != "antlr" })
configurations["jvmMainApi"].apply {
setExtendsFrom(extendsFrom.filter { it.name != "antlr" })
}

/**
* By default, antlr doesn't know about MPP, so we wire everything manually
*/
kotlin.sourceSets.getByName("jvmMain").kotlin.srcDir(file("build/generated-src/antlr/main"))
sourceSets.getByName("main").java.srcDir(file("build/generated-src/antlr/main"))

// See https://github.com/gradle/gradle/issues/19555
tasks.named("compileKotlin") {
tasks.named("compileKotlinJvm") {
dependsOn("generateGrammarSource")
}
tasks.named("compileTestKotlin") {
// See https://github.com/gradle/gradle/issues/19555
tasks.named("compileJava") {
dependsOn("generateGrammarSource")
}
tasks.named("compileKotlinJvm") {
dependsOn("generateTestGrammarSource")
}
tasks.named("compileJmhKotlin") {
dependsOn("generateJmhGrammarSource")
tasks.named("jvmSourcesJar") {
dependsOn("generateGrammarSource")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.apollographql.apollo3.ast

import okio.BufferedSource

internal actual fun parseDocumentWithAntlr(
source: BufferedSource,
filePath: String?,
): GQLResult<GQLDocument> {
throw UnsupportedOperationException("Antlr parser implementation is for the JVM")
}

internal actual fun parseValueWithAntlr(
source: BufferedSource,
filePath: String?,
): GQLResult<GQLValue> {
throw UnsupportedOperationException("Antlr parser implementation is for the JVM")
}

internal actual fun parseTypeWithAntlr(
source: BufferedSource,
filePath: String?,
): GQLResult<GQLType> {
throw UnsupportedOperationException("Antlr parser implementation is for the JVM")
}

internal actual fun parseSelectionsWithAntlr(
source: BufferedSource,
filePath: String?,
): GQLResult<List<GQLSelection>> {
throw UnsupportedOperationException("Antlr parser implementation is for the JVM")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.apollographql.apollo3.ast

import okio.FileSystem

internal actual val HOST_FILESYSTEM: FileSystem
get() = FileSystem.SYSTEM
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,13 @@ package com.apollographql.apollo3.ast
import com.apollographql.apollo3.annotations.ApolloExperimental
import com.apollographql.apollo3.annotations.ApolloInternal
import com.apollographql.apollo3.ast.internal.ExecutableValidationScope
import com.apollographql.apollo3.ast.internal.LexerException
import com.apollographql.apollo3.ast.internal.Parser
import com.apollographql.apollo3.ast.internal.ParserException
import com.apollographql.apollo3.ast.internal.LexerException
import com.apollographql.apollo3.ast.internal.antlrParse
import com.apollographql.apollo3.ast.internal.toGQLDocument
import com.apollographql.apollo3.ast.internal.toGQLSelection
import com.apollographql.apollo3.ast.internal.toGQLType
import com.apollographql.apollo3.ast.internal.toGQLValue
import com.apollographql.apollo3.ast.internal.validateSchema
import okio.BufferedSource
import okio.use
import kotlin.jvm.JvmName

/**
* Parses the source to a [Schema], throwing on parsing or validation errors.
Expand Down Expand Up @@ -47,14 +44,19 @@ private fun <T: Any> BufferedSource.parseInternal(filePath: String?, withSourceL

class ParserOptions(
val useAntlr: Boolean = false,
val allowEmpty: Boolean = true,
val allowEmptyDocuments: Boolean = true,
val withSourceLocation: Boolean = true
) {
companion object {
val Default = ParserOptions()
}
}

expect internal fun parseDocumentWithAntlr(source: BufferedSource, filePath: String?): GQLResult<GQLDocument>
expect internal fun parseValueWithAntlr(source: BufferedSource, filePath: String?): GQLResult<GQLValue>
expect internal fun parseTypeWithAntlr(source: BufferedSource, filePath: String?): GQLResult<GQLType>
expect internal fun parseSelectionsWithAntlr(source: BufferedSource, filePath: String?): GQLResult<List<GQLSelection>>

/**
* Parses the source to a [GQLDocument], validating the syntax but not the contents of the document.
*
Expand All @@ -68,9 +70,9 @@ class ParserOptions(
@ApolloExperimental
fun BufferedSource.parseAsGQLDocument(filePath: String? = null, options: ParserOptions = ParserOptions.Default): GQLResult<GQLDocument> {
return if (options.useAntlr) {
antlrParse(this, filePath, { it.document() }, { it.toGQLDocument(filePath) })
parseDocumentWithAntlr(this, filePath)
} else {
parseInternal(filePath, options.withSourceLocation) { parseDocument(options.allowEmpty) }
parseInternal(filePath, options.withSourceLocation) { parseDocument(options.allowEmptyDocuments) }
}
}

Expand All @@ -80,17 +82,26 @@ fun BufferedSource.parseAsGQLDocument(filePath: String? = null, options: ParserO
* Closes [BufferedSource]
*/
@ApolloExperimental
fun BufferedSource.parseAsGQLValue(filePath: String? = null): GQLResult<GQLValue> {
return antlrParse(this, filePath, { it.value() }, { it.toGQLValue(filePath) })
fun BufferedSource.parseAsGQLValue(filePath: String? = null, options: ParserOptions = ParserOptions.Default): GQLResult<GQLValue> {
return if (options.useAntlr) {
parseValueWithAntlr(this, filePath)
} else {
parseInternal(filePath, options.withSourceLocation) { parseValue() }
}
}

/**
* Parses the source to a [GQLType], validating the syntax but not the contents of the value.
*
* Closes [BufferedSource]
*/
@ApolloExperimental
fun BufferedSource.parseAsGQLType(filePath: String? = null): GQLResult<GQLType> {
return antlrParse(this, filePath, { it.type() }, { it.toGQLType(filePath) })
fun BufferedSource.parseAsGQLType(filePath: String? = null, options: ParserOptions = ParserOptions.Default): GQLResult<GQLType> {
return if (options.useAntlr) {
parseTypeWithAntlr(this, filePath)
} else {
parseInternal(filePath, options.withSourceLocation) { parseType() }
}
}

/**
Expand All @@ -99,8 +110,12 @@ fun BufferedSource.parseAsGQLType(filePath: String? = null): GQLResult<GQLType>
* Closes [BufferedSource]
*/
@ApolloExperimental
fun BufferedSource.parseAsGQLSelections(filePath: String? = null): GQLResult<List<GQLSelection>> {
return antlrParse(this, filePath, { it.selections() }, { it.selection().map { it.toGQLSelection(filePath) } })
fun BufferedSource.parseAsGQLSelections(filePath: String? = null, options: ParserOptions = ParserOptions.Default): GQLResult<List<GQLSelection>> {
return if (options.useAntlr) {
parseSelectionsWithAntlr(this, filePath)
} else {
parseInternal(filePath, options.withSourceLocation) { parseSelections() }
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package com.apollographql.apollo3.ast

import java.io.File
import java.io.IOException
import okio.FileSystem
import okio.IOException
import okio.Path.Companion.toPath
import okio.buffer


expect internal val HOST_FILESYSTEM: FileSystem

open class SourceAwareException(
val error: String,
Expand All @@ -23,7 +28,7 @@ open class SourceAwareException(
val preview = if (sourceLocation?.filePath != null && sourceLocation.line >= 1 && sourceLocation.column >= 1) {
val filePath = sourceLocation.filePath
val document = try {
File(filePath).readText()
HOST_FILESYSTEM.source(filePath.toPath()).buffer().readUtf8()
} catch (e: IOException) {
throw RuntimeException("Failed to read GraphQL file `$this`", e)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package com.apollographql.apollo3.ast

import okio.buffer
import okio.source
import com.apollographql.apollo3.ast.internal.apollo_v0_1_definitionsStr
import com.apollographql.apollo3.ast.internal.apollo_v0_2_definitionsStr
import com.apollographql.apollo3.ast.internal.builtinsDefinitionsStr
import com.apollographql.apollo3.annotations.ApolloDeprecatedSince
import com.apollographql.apollo3.ast.internal.linkDefinitionsStr
import okio.Buffer

fun GQLDocument.withBuiltinDefinitions(): GQLDocument {
return withDefinitions(builtinDefinitions())
Expand All @@ -14,28 +18,33 @@ fun GQLDocument.withoutBuiltinDefinitions(): GQLDocument {
/**
* Definitions from the spec
*/
fun builtinDefinitions() = definitionsFromResources("builtins.graphqls")
fun builtinDefinitions() = definitionsFromString(builtinsDefinitionsStr)

/**
* The @link definition for bootstrapping
*
* https://specs.apollo.dev/link/v1.0/
*/
fun linkDefinitions() = definitionsFromResources("link.graphqls")
fun linkDefinitions() = definitionsFromString(linkDefinitionsStr)

@Deprecated("Use apolloDefinitions(version) instead", ReplaceWith("apolloDefinitions(\"v0.1\")"))
fun apolloDefinitions() = apolloDefinitions("v0.1")
@ApolloDeprecatedSince(ApolloDeprecatedSince.Version.v3_5_1)
fun apolloDefinitions() = definitionsFromString(apollo_v0_1_definitionsStr)

/**
* Extra apollo specific definitions from https://specs.apollo.dev/kotlin_labs/<[version]>
*/
fun apolloDefinitions(version: String) = definitionsFromResources("apollo-$version.graphqls")
fun apolloDefinitions(version: String): List<GQLDefinition> {
return definitionsFromString(when(version) {
"v0.1" -> apollo_v0_1_definitionsStr
"v0.2" -> apollo_v0_2_definitionsStr
else -> error("Apollo definitions $version are not supported")
})
}

private fun definitionsFromResources(name: String): List<GQLDefinition> {
return GQLDocument::class.java.getResourceAsStream("/$name")!!
.source()
.buffer()
.parseAsGQLDocument("($name)")
private fun definitionsFromString(string: String): List<GQLDefinition> {
return Buffer().writeUtf8(string)
.parseAsGQLDocument(null)
.getOrThrow()
.definitions
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
@file:JvmMultifileClass
@file:JvmName("GqlnodeKt")
package com.apollographql.apollo3.ast

import okio.Buffer
import okio.BufferedSink
import okio.buffer
import okio.sink
import java.io.File
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName

fun GQLNode.toUtf8(sink: BufferedSink, indent: String = " ") {
val writer = SDLWriter(sink, indent)
writer.write(this)
}

fun GQLNode.toUtf8(file: File, indent: String = " ") = file.outputStream().sink().buffer().use {
toUtf8(it, indent)
}

fun GQLNode.toUtf8(indent: String = " "): String {
val buffer = Buffer()
toUtf8(buffer, indent)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.apollographql.apollo3.ast

import com.apollographql.apollo3.ast.internal.ExecutableValidationScope
import kotlin.jvm.JvmOverloads

fun GQLOperationDefinition.rootTypeDefinition(schema: Schema) = when (operationType) {
"query" -> schema.queryTypeDefinition
Expand Down
Loading

0 comments on commit 18963c3

Please sign in to comment.