Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: ktorio/ktor-plugin-registry
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: main
Choose a base ref
...
head repository: ktorio/ktor-plugin-registry
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: hk24/js-support
Choose a head ref
Can’t automatically merge. Don’t worry, you can still create the pull request.
  • 5 commits
  • 19 files changed
  • 2 contributors

Commits on Sep 18, 2024

  1. Copy the full SHA
    d860ba4 View commit details
  2. Clean up install

    bjhham committed Sep 18, 2024
    Copy the full SHA
    fd264db View commit details

Commits on Sep 19, 2024

  1. Copy the full SHA
    3e74b5a View commit details
  2. Add some hacked shiny stuff

    osipxd committed Sep 19, 2024
    Copy the full SHA
    a31833f View commit details
  3. Copy the full SHA
    cd2ad4c View commit details
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -77,7 +77,7 @@ sourceSets {
}

detekt {
toolVersion = libs.versions.detekt.version.get()
toolVersion = libs.versions.detekt.get()
config.setFrom(file("detekt.yml"))
buildUponDefaultConfig = true
}
Original file line number Diff line number Diff line change
@@ -57,11 +57,18 @@ data class ArtifactReference(
val group: String? = null,
val name: String,
val version: ArtifactVersion,
val function: String? = null,
) {
companion object {
private val functionReference = Regex("""(\w+)\((.+?)\)""")
private val referenceStringRegex = Regex("""(?:(.+?):)?(.+?):(.+)""")

fun parse(text: String, defaultGroup: String? = null, versionVariables: Map<String, String> = emptyMap()): ArtifactReference =
functionReference.matchEntire(text)?.destructured?.let { (function, reference) ->
parseReference(reference, defaultGroup, versionVariables).copy(function = function)
} ?: parseReference(text, defaultGroup, versionVariables)

private fun parseReference(text: String, defaultGroup: String? = null, versionVariables: Map<String, String> = emptyMap()) =
referenceStringRegex.matchEntire(text)?.destructured?.let { (group, name, version) ->
ArtifactReference(
group.takeIf(String::isNotEmpty) ?: defaultGroup,
Original file line number Diff line number Diff line change
@@ -15,14 +15,16 @@ import kotlin.io.path.outputStream
*/
fun Sequence<PluginReference>.allArtifactsForVersion(ktorRelease: String): Sequence<String> =
flatMap { plugin ->
plugin.allArtifactsForVersion(ktorRelease).map { artifact ->
with(artifact) {
"$group:$name:" + when(version) {
is MatchKtor -> ktorRelease
else -> version.toString()
plugin.allArtifactsForVersion(ktorRelease)
.filter { it.function == null } // TODO ignore function deps for now
.map { artifact ->
with(artifact) {
"$group:$name:" + when(version) {
is MatchKtor -> ktorRelease
else -> version.toString()
}
}
}
}
}

/**
37 changes: 19 additions & 18 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
[versions]
kotlin-version = "2.0.20"
kaml-version = "0.61.0"
logback-version = "1.5.7"
serialization-version = "1.7.2"
maven-artifact-version = "3.9.9"
detekt-version = "1.23.6"
jgit-version="6.10.0.202406032230-r"
compress-version="1.27.1"
kotlin = "2.0.20"
kaml = "0.61.0"
logback = "1.5.7"
serialization = "1.7.2"
maven-artifact = "3.9.9"
detekt = "1.23.6"
jgit="6.10.0.202406032230-r"
compress="1.27.1"
kotlinx-browser="0.1"

[libraries]
kotlin-compiler = { module = "org.jetbrains.kotlin:kotlin-compiler", version.ref = "kotlin-version" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization-version" }
kaml = { module = "com.charleskorn.kaml:kaml", version.ref = "kaml-version" }
logback-classic = { module = "ch.qos.logback:logback-classic", version.ref = "logback-version" }
maven-artifact = { module = "org.apache.maven:maven-artifact", version.ref = "maven-artifact-version" }
jgit = { module = "org.eclipse.jgit:org.eclipse.jgit", version.ref = "jgit-version" }
apache-compress = { module = "org.apache.commons:commons-compress", version.ref = "compress-version" }
kotlin-compiler = { module = "org.jetbrains.kotlin:kotlin-compiler", version.ref = "kotlin" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization" }
kaml = { module = "com.charleskorn.kaml:kaml", version.ref = "kaml" }
logback-classic = { module = "ch.qos.logback:logback-classic", version.ref = "logback" }
maven-artifact = { module = "org.apache.maven:maven-artifact", version.ref = "maven-artifact" }
jgit = { module = "org.eclipse.jgit:org.eclipse.jgit", version.ref = "jgit" }
apache-compress = { module = "org.apache.commons:commons-compress", version.ref = "compress" }

[plugins]
detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt-version" }
serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin-version" }
jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin-version" }
detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }
serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
Original file line number Diff line number Diff line change
@@ -25,8 +25,8 @@ install(Authentication) {

## API

| **Param** | **Required** | **Description** |
|-----------|--------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| adminFile | Required | [File](https://docs.oracle.com/javase/8/docs/api/java/io/File.html) instance, pointing to your Service account for your Firebase project. See [sample project](https://github.com/krizzu/firebase-auth-provider/blob/main/sample/README.md) to learn more. |
| validate | Required | Lambda receiving decoded and verified [FirebaseToken](https://firebase.google.com/docs/reference/admin/java/reference/com/google/firebase/auth/FirebaseToken), expected to return Principal, if user is authorized or null otherwise. |
| realm | Optional | String describing the protected area or the scope of protection. This could be a message like "Access to the staging site" or similar, so that the user knows to which space they are trying to get access to. Defaults to "Ktor Server" |
| **Param** | **Required** | **Description** |
|-----------|--------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| adminFile | Required | [File](https://docs.oracle.com/javase/8/docs/api/java/io/File.html) instance, pointing to your Service account for your Firebase project. See [sample project](https://github.com/krizzu/firebase-auth-provider/blob/main/sample/README.md) to learn more. |
| validate | Required | Lambda receiving decoded and verified [FirebaseToken](https://firebase.google.com/docs/reference/admin/java/reference/com/google/firebase/auth/FirebaseToken), expected to return Principal, if user is authorized or null otherwise. |
| realm | Optional | String describing the protected area or the scope of protection. This could be a message like "Access to the staging site" or similar, so that the user knows to which space they are trying to get access to. Defaults to "Ktor Server" |
48 changes: 48 additions & 0 deletions plugins/server/io.ktor/htmx/3.0.0-rc-1/documentation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
Create a project using [htmx](https://htmx.org).

This plugin uses the `kotlinx-html` DSL for templating responses, and provides extra support for various HTMX features.

## Usage

Inserting HTMX tags into your HTML DSL:

```kotlin
button {
attributes.hx {
get = "/?page=$nextPage"
target = Target { "#replaceMe" }
swap = HxSwap.outerHTML
trigger = "click[console.log('Hello!')||true]"
}

+"Load More Agents..."
}
```

Reading HTMX headers:

```kotlin
if (call.request.hx.isBoosted) {
call.respondHtmlFragment {
div {
id = "replaceMe"
+"Loading..."
}
}
}
```

Routing for HTMX endpoints:

```kotlin
hx.get("/", target = Id("replaceMe")) {
val page = requireNotNull(call.parameters["page"]).toInt()
require(page > 0) { "Page must be greater than 0" }

log.info("Current URL: ${call.request.hx.currentUrl.toString()}")
call.respondHtmlFragment {
AgentsRowsPage(AgentRepository.loadAgents(page), nextPage = page + 1)
}
}
```

7 changes: 7 additions & 0 deletions plugins/server/io.ktor/htmx/3.0.0-rc-1/install.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import io.ktor.server.application.*
import io.ktor.server.plugins.htmx.*
import io.ktor.server.response.*

public fun Application.configureTemplating() {
install(Htmx)
}
6 changes: 6 additions & 0 deletions plugins/server/io.ktor/htmx/3.0.0-rc-1/main.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import kotlinx.browser.window

fun main() {
// Use Kotlin's `js` function to require the library and assign it to `window`
window.asDynamic().htmx = js("require('htmx.org')")
}
22 changes: 22 additions & 0 deletions plugins/server/io.ktor/htmx/3.0.0-rc-1/manifest.ktor.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: HTMX
description: Provides HTMX front-end support
vcsLink: https://github.com/ktorio/ktor # TODO link to source
license: Apache 2.0
category: Templating
prerequisites:
- routing
- html-dsl
installation:
default: install.kt
in_routing: routing.kt
js_source_file_kt: main.kt
gradle:
plugins:
- id: org.jetbrains.kotlin.plugin.assignment
version: LAST_KOTLIN_VERSION
repositories:
- url: https://packages.jetbrains.team/maven/p/ktor-htmx-hackathon-2024/htmx
- url: https://packages.jetbrains.team/maven/p/ktor-htmx-hackathon-2024/kotlinx-html
platforms:
- jvm
- js
50 changes: 50 additions & 0 deletions plugins/server/io.ktor/htmx/3.0.0-rc-1/routing.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.html.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.plugins.htmx.*
import io.ktor.server.routing.*
import kotlinx.html.*
import org.jetbrains.hackathon.extension.html.*
import org.jetbrains.htmx.*
import java.io.File

fun Routing.configureRouting() {
val scriptPattern = Regex(".+?\\.js(\\.map)?")

// Index page
get("/") {
call.respondHtml {
head {
title("HTMX Demo")
script { src = "main.js" }
}
body {
button {
attributes["hx-get"] = "/"
attributes["hx-swap"] = "innerHTML"

+"Test"
}
}
}
}

// Htmx endpoint
hx.get("/") {
call.respondHtmlFragment {
div {
+"Hello, HTMX"
}
}
}

get(scriptPattern) {
val requestPath = call.request.path()
val resolvedFile = File("build/dist/js/productionExecutable/$requestPath")
if (resolvedFile.exists())
call.respondFile(resolvedFile)
else call.respond(HttpStatusCode.NotFound)
}
}
3 changes: 3 additions & 0 deletions plugins/server/io.ktor/htmx/versions.ktor.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"[3.0.0-rc-1,)":
- org.jetbrains.hk24:extension-ktor:1.0.0-SNAPSHOT
- npm(htmx.org:2.0.2)
9 changes: 9 additions & 0 deletions plugins/server/io.ktor/live-reload/2.0/documentation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
When developing websites for Ktor, you can enable browser refreshing whenever project files change. This allows for rapid feedback when making changes to your codebase.

The plugin works by injecting a small script in outbound HTML documents that will wait for refresh messages from the server.

# Usage

When the plugin is installed and `developmentMode` is enabled, a GET endpoint will be created that keeps connections open until the server is refreshed.

To configure your project for auto-reload, follow the directions found here: [https://ktor.io/docs/server-auto-reload.html](https://ktor.io/docs/server-auto-reload.html)
6 changes: 6 additions & 0 deletions plugins/server/io.ktor/live-reload/2.0/install.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import io.ktor.server.application.*
import io.ktor.server.plugins.live.reload.*

fun Application.configure() {
install(LiveReload)
}
5 changes: 5 additions & 0 deletions plugins/server/io.ktor/live-reload/2.0/manifest.ktor.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name: LiveReload
description: Refreshes your browser after changes to project files
vcsLink: https://github.com/ktorio/ktor # TODO link to source
license: Apache 2.0
category: HTTP
Empty file.
2 changes: 2 additions & 0 deletions plugins/server/io.ktor/live-reload/versions.ktor.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"[2.0,)":
- ktor-server-live-reload:3.0.0-rc-2-SNAPSHOT
2 changes: 2 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -15,6 +15,8 @@ dependencyResolutionManagement {
name = "SpaceKotlinJsWrappers"
}
maven("https://packages.confluent.io/maven/")
maven("https://packages.jetbrains.team/maven/p/ktor-htmx-hackathon-2024/htmx")
maven("https://packages.jetbrains.team/maven/p/ktor-htmx-hackathon-2024/kotlinx-html")
}
}

31 changes: 20 additions & 11 deletions src/main/kotlin/io/ktor/plugins/registry/utils/CodeAnalysis.kt
Original file line number Diff line number Diff line change
@@ -31,6 +31,7 @@ import org.slf4j.LoggerFactory
import java.io.File
import java.nio.file.Path
import kotlin.io.path.absolutePathString
import kotlin.io.path.readText

class CodeAnalysis(private val classpathJars: List<Path> = emptyList()) {

@@ -44,17 +45,22 @@ class CodeAnalysis(private val classpathJars: List<Path> = emptyList()) {
private val pluginAnalyzers = mutableMapOf<Path, PluginCodeAnalyzer>()

fun findErrorsAndThrow(sourceRoot: Path, plugin: PluginReference) {
findErrors(sourceRoot).ifNotEmpty {
logger.error(
"Compilation error(s) found in plugin ${plugin.id}:" +
joinToString("\n", "\n") {
with(it) {
"${sourceRoot.absolutePathString()}/$file:$lineNumber:$column: $message"
findErrors(sourceRoot)
.filter { error ->
// TODO include JS std lib for these files
!sourceRoot.resolve(error.file).readText().contains("kotlinx.browser")
}
.ifNotEmpty {
logger.error(
"Compilation error(s) found in plugin ${plugin.id}:" +
joinToString("\n", "\n") {
with(it) {
"${sourceRoot.absolutePathString()}/$file:$lineNumber:$column: $message"
}
}
}
)
throw IllegalArgumentException("Failed to compile sources for plugin: ${plugin.id}")
}
)
throw IllegalArgumentException("Failed to compile sources for plugin: ${plugin.id}")
}
}

private fun findErrors(sourceRoot: Path) =
@@ -275,9 +281,12 @@ enum class CodeInjectionSite(
// In application resources folder as a separate resource file
RESOURCES(CodeExtractionMethod.FILE),

// In separate file near the code
// In a separate file near the code
SOURCE_FILE_KT(CodeExtractionMethod.FILE),

// In a separate file in JS source
JS_SOURCE_FILE_KT(CodeExtractionMethod.FILE),

// In application.conf file
APPLICATION_CONF(CodeExtractionMethod.VERBATIM, "application.conf"),

Loading