diff --git a/buildSrc/src/main/kotlin/dokka-convention.gradle.kts b/buildSrc/src/main/kotlin/dokka-convention.gradle.kts index 4d21442b641..585ce416c07 100644 --- a/buildSrc/src/main/kotlin/dokka-convention.gradle.kts +++ b/buildSrc/src/main/kotlin/dokka-convention.gradle.kts @@ -97,11 +97,15 @@ tasks.register("trimNavigationFiles") { val navigation = moduleDir.resolve("navigation.html").toFile() val doc = Jsoup.parse(navigation) - // Fix navigation links - doc.select("a[href^='../../../../']").forEach { anchor -> - val originalHref = anchor.attr("href") - val trimmedHref = originalHref.replace("../../../../", "") - anchor.attr("href", trimmedHref) + // Remove all parent directory elements from all navigation links + doc.select("a[href^=../]").forEach { anchor -> + var href = anchor.attr("href") + + while (href.startsWith("../")) { + href = href.removePrefix("../") + } + + anchor.attr("href", href) } // Trim side menus diff --git a/docs/dokka-presets/scripts/custom-navigation-loader.js b/docs/dokka-presets/scripts/custom-navigation-loader.js index b42f17cf41c..9c14653826d 100644 --- a/docs/dokka-presets/scripts/custom-navigation-loader.js +++ b/docs/dokka-presets/scripts/custom-navigation-loader.js @@ -5,27 +5,27 @@ * https://sdk.amazonaws.com/kotlin/api/latest/index.html -> index.html * https://sdk.amazonaws.com/kotlin/api/latest/s3/index.html -> s3 * https://sdk.amazonaws.com/kotlin/api/latest/s3/aws.sdk.kotlin.services.s3/index.html -> s3 + * https://sdk.amazonaws.com/kotlin/api/1.4.109/s3/index.html -> s3 */ function extractModulePath(href) { try { - const url = new URL(href, window.location.origin); - const pathSegments = url.pathname.split('/').filter(Boolean); - - var moduleIndex = -1; - - for (let i = 1; i < pathSegments.length; i++) { - if (pathSegments[i].includes('.')) { - moduleIndex = i-1; - break; - } + const segments = new URL(href, window.location.origin) + .pathname + .split('/') + .filter(Boolean); // drop empty parts + + // the URL pattern is always ".../kotlin/api//..." in production + const apiIndex = segments.indexOf('api'); + + if (apiIndex !== -1) { + // segment after "api" is the version ("latest", "1.4.109", etc.) + // segment after _that_ is the module name (or "index.html" if we're at the root) + return segments[apiIndex + 2] ?? 'index.html'; } - if (moduleIndex === -1) { - return "index.html"; - } else { - return pathSegments.slice(0, moduleIndex + 1).join("/"); - } - } catch (error) { + // locally-hosted docs don't have /kotlin/api segment + return segments[0] ?? 'index.html'; + } catch { return null; } } diff --git a/services/timestreamquery/e2eTest/src/EndpointDiscoveryTest.kt b/services/timestreamquery/e2eTest/src/EndpointDiscoveryTest.kt deleted file mode 100644 index 883278f1891..00000000000 --- a/services/timestreamquery/e2eTest/src/EndpointDiscoveryTest.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ -package aws.sdk.kotlin.services.timestreamquery - -import aws.sdk.kotlin.services.timestreamquery.model.DescribeEndpointsResponse -import aws.sdk.kotlin.services.timestreamquery.model.ListScheduledQueriesResponse -import aws.smithy.kotlin.runtime.client.ResponseInterceptorContext -import aws.smithy.kotlin.runtime.client.operationName -import aws.smithy.kotlin.runtime.http.interceptors.HttpInterceptor -import aws.smithy.kotlin.runtime.http.request.HttpRequest -import aws.smithy.kotlin.runtime.http.response.HttpResponse -import kotlinx.coroutines.runBlocking -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertNotNull -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance - -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class EndpointDiscoveryTest { - @Test - fun testEndpointDiscovery() = runBlocking { - val operationLog = mutableListOf() - var discoveredHost: String? = null - - val interceptor = object : HttpInterceptor { - override fun readAfterExecution( - context: ResponseInterceptorContext, - ) { - operationLog += context.executionContext.operationName!! - - when (val response = context.response.getOrNull()) { - is DescribeEndpointsResponse -> discoveredHost = response.endpoints!!.first().address - - is ListScheduledQueriesResponse -> { - // Make sure every request _except_ DescribeEndpoints uses the discovered endpoint - assertNotNull(discoveredHost) - assertEquals(discoveredHost, context.protocolRequest!!.url.host.toString()) - } - - else -> error("Unexpected response ${context.response}") - } - } - } - - TimestreamQueryClient { - region = "us-west-2" - interceptors += interceptor - }.use { tsq -> - tsq.listScheduledQueries() - - // Have to discover the endpoint the first time - assertEquals(listOf("DescribeEndpoints", "ListScheduledQueries"), operationLog) - operationLog.clear() - - tsq.listScheduledQueries() - - // Don't have to discover the endpoint again because it's cached - assertEquals(listOf("ListScheduledQueries"), operationLog) - } - } -} diff --git a/services/timestreamwrite/e2eTest/src/EndpointDiscoveryTest.kt b/services/timestreamwrite/e2eTest/src/EndpointDiscoveryTest.kt deleted file mode 100644 index 8beaae424e5..00000000000 --- a/services/timestreamwrite/e2eTest/src/EndpointDiscoveryTest.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ -package aws.sdk.kotlin.services.timestreamwrite - -import aws.sdk.kotlin.services.timestreamwrite.model.DescribeEndpointsResponse -import aws.sdk.kotlin.services.timestreamwrite.model.ListDatabasesResponse -import aws.smithy.kotlin.runtime.client.ResponseInterceptorContext -import aws.smithy.kotlin.runtime.client.operationName -import aws.smithy.kotlin.runtime.http.interceptors.HttpInterceptor -import aws.smithy.kotlin.runtime.http.request.HttpRequest -import aws.smithy.kotlin.runtime.http.response.HttpResponse -import kotlinx.coroutines.runBlocking -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertNotNull -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance - -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class EndpointDiscoveryTest { - @Test - fun testEndpointDiscovery() = runBlocking { - val operationLog = mutableListOf() - var discoveredHost: String? = null - - val interceptor = object : HttpInterceptor { - override fun readAfterExecution( - context: ResponseInterceptorContext, - ) { - operationLog += context.executionContext.operationName!! - - when (val response = context.response.getOrNull()) { - is DescribeEndpointsResponse -> discoveredHost = response.endpoints!!.first().address - - is ListDatabasesResponse -> { - // Make sure every request _except_ DescribeEndpoints uses the discovered endpoint - assertNotNull(discoveredHost) - assertEquals(discoveredHost, context.protocolRequest!!.url.host.toString()) - } - - else -> error("Unexpected response ${context.response}") - } - } - } - - TimestreamWriteClient { - region = "us-west-2" - interceptors += interceptor - }.use { tsw -> - tsw.listDatabases() - - // Have to discover the endpoint the first time - assertEquals(listOf("DescribeEndpoints", "ListDatabases"), operationLog) - operationLog.clear() - - tsw.listDatabases() - - // Don't have to discover the endpoint again because it's cached - assertEquals(listOf("ListDatabases"), operationLog) - } - } -}