Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 26 additions & 8 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import dev.detekt.gradle.Detekt
import dev.detekt.gradle.extensions.DetektExtension
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.gradle.api.tasks.testing.logging.TestLogEvent
import org.gradle.kotlin.dsl.withType

plugins {
alias(libs.plugins.kotlin.jvm)
Expand Down Expand Up @@ -46,12 +45,13 @@ dependencies {
kover(project(kotestModule))
}

dokka {
moduleName.set("ReadingBat")
pluginsConfiguration.html {
homepageLink.set(repoUrl)
footerMessage.set(projectName)
}
// Dokka config is root-level (aggregate docs); the plugin is applied via the plugins {} block
// above. It can't go in allprojects {} — subprojects don't have the Dokka plugin applied until
// the subprojects {} block below runs, so the `dokka` extension wouldn't exist yet there.
configureDokka()

allprojects {
configureVersions()
}

subprojects {
Expand All @@ -68,7 +68,6 @@ subprojects {
configureKotlinter()
configureDetekt()
configureSecrets()
configureVersions()
}

fun Project.configureKotlin() {
Expand All @@ -83,6 +82,15 @@ fun Project.configureKotlin() {
kotlin {
jvmToolchain(jvmTargetVersion.toInt())

// Collection literals (`val x: List<Int> = [1, 2, 3]`) are an experimental Kotlin 2.4
// feature gated behind this flag. Removing it breaks every `[...]` literal in the
// sources. Note this flag applies to project sources only -- it is NOT in effect for
// the JSR-223 script engine that evaluates the content DSL at runtime, so DSL content
// files must keep using listOf()/mutableListOf().
compilerOptions {
freeCompilerArgs.add("-Xcollection-literals")
}

sourceSets.all {
listOf(
"kotlin.ExperimentalStdlibApi",
Expand Down Expand Up @@ -202,6 +210,16 @@ fun Project.configureTesting() {
}
}

fun Project.configureDokka() {
dokka {
moduleName.set("ReadingBat")
pluginsConfiguration.html {
homepageLink.set(repoUrl)
footerMessage.set(projectName)
}
}
}

fun Project.configureVersions() {
// A pre-release qualifier is a `.` or `-` delimiter followed by a known unstable
// keyword. `m\d` matches milestones (`-M1`/`.M2`) without catching stable classifiers
Expand Down
16 changes: 8 additions & 8 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,37 @@ jvm = "17"
# Plugin versions
buildconfig = "6.0.10"
detekt = "2.0.0-alpha.5"
kotlin = "2.4.0"
kotlinter = "5.5.0"
kover = "0.9.8"
kotlin = "2.4.10"
kotlinter = "5.6.0"
kover = "0.9.9"
dokka = "2.2.0"
maven-publish = "0.37.0"
versions = "0.54.0"

# Library versions
cloud = "1.28.6"
cloud = "1.29.0"
commons = "1.15.0"
exposed = "1.3.1"
flexmark = "0.64.8"
flyway = "12.11.0"
flyway = "13.0.0"
github-api = "1.330"
hikari = "7.1.0"
java-scriptengine = "2.0.0"
khealth = "3.0.1"
kotest = "6.2.2"
kotest = "6.2.3"
ktor = "3.5.1"
logback = "1.5.38"
logging = "7.0.12"
pgjdbc = "0.8.9"
playwright = "1.61.0"
postgres = "42.7.13"
prometheus = "0.16.0"
prometheus-proxy = "3.2.0"
prometheus-proxy = "4.0.0"
python = "2.7.4"
resend = "4.13.0"
serialization = "1.11.0"
testcontainers = "1.21.4"
utils = "3.1.0"
utils = "3.2.1"

[libraries]
# Serialization
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ class FunctionInfo(
*/
internal fun splitTopLevelCommas(csv: String): List<String> {
if (csv.isBlank()) return emptyList()
val elements = mutableListOf<String>()
val elements: MutableList<String> = []
val current = StringBuilder()
var quoteChar: Char? = null
for (c in csv) {
Expand Down
40 changes: 20 additions & 20 deletions readingbat-core/src/main/kotlin/com/readingbat/common/Metrics.kt
Original file line number Diff line number Diff line change
Expand Up @@ -199,80 +199,80 @@ class Metrics {
SamplerGaugeCollector(
"request_timing_map_size",
"Request timing map size",
labelNames = listOf(AGENT_ID),
labelValues = listOf(agentLaunchId()),
labelNames = [AGENT_ID],
labelValues = [agentLaunchId()],
data = { requestTimingMap.size.toDouble() },
)

SamplerGaugeCollector(
"geo_map_size",
"IP Geo map size",
labelNames = listOf(AGENT_ID),
labelValues = listOf(agentLaunchId()),
labelNames = [AGENT_ID],
labelValues = [agentLaunchId()],
data = { geoInfoMap.size.toDouble() },
)

SamplerGaugeCollector(
"content_map_size",
"Content map size",
labelNames = listOf(AGENT_ID),
labelValues = listOf(agentLaunchId()),
labelNames = [AGENT_ID],
labelValues = [agentLaunchId()],
data = { contentSource().contentMap.size.toDouble() },
)

SamplerGaugeCollector(
"user_id_cache_size",
"User ID cache size",
labelNames = listOf(AGENT_ID),
labelValues = listOf(agentLaunchId()),
labelNames = [AGENT_ID],
labelValues = [agentLaunchId()],
data = { userIdCache.size.toDouble() },
)

SamplerGaugeCollector(
"user_email_cache_size",
"User email cache size size",
labelNames = listOf(AGENT_ID),
labelValues = listOf(agentLaunchId()),
labelNames = [AGENT_ID],
labelValues = [agentLaunchId()],
data = { emailCache.size.toDouble() },
)

SamplerGaugeCollector(
"sources_cache_size",
"Sources cache size",
labelNames = listOf(AGENT_ID),
labelValues = listOf(agentLaunchId()),
labelNames = [AGENT_ID],
labelValues = [agentLaunchId()],
data = { contentSource().functionInfoMap.size.toDouble() },
)

SamplerGaugeCollector(
"websocket_connection_list_size",
"Websocket connection list size",
labelNames = listOf(AGENT_ID),
labelValues = listOf(agentLaunchId()),
labelNames = [AGENT_ID],
labelValues = [agentLaunchId()],
data = { answerWsConnections.size.toDouble() },
)

SamplerGaugeCollector(
"active_users_1min_count",
"Active users in last 1 min count",
labelNames = listOf(AGENT_ID),
labelValues = listOf(agentLaunchId()),
labelNames = [AGENT_ID],
labelValues = [agentLaunchId()],
data = { activeSessions(1.minutes).toDouble() },
)

SamplerGaugeCollector(
"active_users_15mins_count",
"Active users in last 15 mins count",
labelNames = listOf(AGENT_ID),
labelValues = listOf(agentLaunchId()),
labelNames = [AGENT_ID],
labelValues = [agentLaunchId()],
data = { activeSessions(15.minutes).toDouble() },
)

SamplerGaugeCollector(
"active_users_60mins_count",
"Active users in last 60 mins count",
labelNames = listOf(AGENT_ID),
labelValues = listOf(agentLaunchId()),
labelNames = [AGENT_ID],
labelValues = [agentLaunchId()],
data = { activeSessions(1.hours).toDouble() },
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ open class KtorProperty(
companion object {
private val logger = KotlinLogging.logger {}
private val initialized = AtomicBoolean(false)
private val instances = mutableListOf<KtorProperty>()
private val instances: MutableList<KtorProperty> = []
internal val configStore = java.util.concurrent.ConcurrentHashMap<String, String>()

// Names of properties that have individually had a value assigned via setProperty. Lets the
Expand Down Expand Up @@ -466,7 +466,7 @@ sealed class Property(

/** Returns the ordered list of properties that should be initialized at application startup. */
fun initProperties() =
listOf(
[
DSL_FILE_NAME,
DSL_VARIABLE_NAME,
PROXY_HOSTNAME,
Expand Down Expand Up @@ -503,6 +503,6 @@ sealed class Property(
GOOGLE_OAUTH_CLIENT_ID,
GOOGLE_OAUTH_CLIENT_SECRET,
SESSION_SECRET,
)
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class ChallengeGroup<T : Challenge>(
internal val groupNameSuffix: GroupName,
) {
/** The ordered list of challenges in this group. */
val challenges = mutableListOf<T>()
val challenges: MutableList<T> = []

private val groupPrefix by lazy { pathOf(languageName, groupName) }
private val srcPath get() = languageGroup.srcPath
Expand Down Expand Up @@ -149,7 +149,7 @@ class ChallengeGroup<T : Challenge>(
var includeFilesWithType by IncludeFilesWithType(this, languageType)

private class IncludeFiles<T : Challenge>(val group: ChallengeGroup<T>, val languageType: LanguageType) {
val includeList = mutableListOf<PatternReturnType>()
val includeList: MutableList<PatternReturnType> = []

operator fun getValue(thisRef: Any?, property: KProperty<*>) = includeList.toString()

Expand All @@ -166,7 +166,7 @@ class ChallengeGroup<T : Challenge>(
}

private class IncludeFilesWithType<T : Challenge>(val group: ChallengeGroup<T>, val languageType: LanguageType) {
val includeList = mutableListOf<PatternReturnType>()
val includeList: MutableList<PatternReturnType> = []

operator fun getValue(thisRef: Any?, property: KProperty<*>): PatternReturnType = PatternReturnType("", Runtime)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,22 +198,22 @@ internal fun evalContentDsl(
*/
internal fun addImports(code: String, variableName: String): String {
val classImports =
listOf(ReadingBatServer::class, GitHubContent::class)
[ReadingBatServer::class, GitHubContent::class]
// .onEach { println("Checking for ${it.javaObjectType.name}") }
.filter { code.contains("${it.javaObjectType.simpleName}(") } // See if the class is referenced
.map { "import ${it.javaObjectType.name}" } // Convert to import stmt
.filterNot { code.contains(it) } // Do not include if import already present
.joinToString("\n") // Turn into String

val funcImports =
listOf(::readingBatContent)
[::readingBatContent]
// .onEach { println("Checking for ${it.name}") }
.filter { code.contains("${it.name}(") } // See if the function is referenced
.map { "import ${it.fqMethodName}" } // Convert to import stmt
.filterNot { code.contains(it) } // Do not include is import already present
.joinToString("\n") // Turn into String

val imports = listOf(classImports, funcImports).filter { it.isNotBlank() }.joinToString("\n")
val imports = [classImports, funcImports].filter { it.isNotBlank() }.joinToString("\n")
return """
$imports${if (imports.isBlank()) "" else "\n\n"}$code
$variableName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class LanguageGroup<T : Challenge>(
val contentRoot get() = languageType.contentRoot

/** The ordered list of challenge groups in this language. */
val challengeGroups = mutableListOf<ChallengeGroup<T>>()
val challengeGroups: MutableList<ChallengeGroup<T>> = []

/**
* The content source for this language's challenge files. Inherits the parent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ enum class LanguageType(val useDoubleQuotes: Boolean, val suffix: String, val sr

companion object {
val defaultLanguageType = Java
val languageTypeList = listOf(Java, Python, Kotlin)
val languageTypeList = [Java, Python, Kotlin]

/** Returns all language types, optionally reordered to put [defaultLanguage] first. */
fun languageTypes(defaultLanguage: LanguageType? = null): List<LanguageType> =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ import kotlin.time.measureTimedValue
@ReadingBatDslMarker
class ReadingBatContent {
internal val timeStamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("M/d/y H:m:ss"))
private val languageList by lazy { listOf(java, python, kotlin) }
private val languageList by lazy { [java, python, kotlin] }
private val languageMap by lazy { languageList.associateBy { it.languageType } }

// contentMap will prevent reading the same content multiple times
Expand All @@ -96,7 +96,7 @@ class ReadingBatContent {
/** Language group for Kotlin challenges. Accessible in the DSL as a property or block receiver. */
val kotlin by lazy { LanguageGroup<KotlinChallenge>(this, Kotlin) }

val languages by lazy { listOf(python, java, kotlin) }
val languages by lazy { [python, java, kotlin] }

val cacheChallenges get() = isProduction() || isTesting()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ sealed class Challenge(

// Allow description updates only if not found in the Content.kt decl
private val isDescriptionSetInDsl by lazy { description.isNotBlank() }
internal val gitpodUrl by lazy { pathOf(repo.sourcePrefix, "blob/$branchName", srcPath, fqName) }
internal val parsedDescription by lazy { MarkdownParser.toHtml(description) }
internal val path by lazy { pathOf(languageName, groupName, challengeName) }

Expand Down Expand Up @@ -308,7 +307,7 @@ class KotlinChallenge(
val funcCode = "\n${extractKotlinFunction(lines)}\n\n"
val invocations = extractKotlinInvocations(lines, KotlinParse.funMainRegex, KotlinParse.kotlinEndRegex)
val script = convertToKotlinScript(lines).also { logger.debug { "Kotlin: $it" } }
val correctAnswers = mutableListOf<Any>()
val correctAnswers: MutableList<Any> = []

logger.debug { "$challengeName return type: $returnType script: \n${script.withLineNumbers()}" }

Expand Down Expand Up @@ -360,7 +359,7 @@ class PythonChallenge(
val funcCode = extractPythonFunction(lines)
val invocations = extractPythonInvocations(lines, PythonParse.defMainRegex, PythonParse.ifMainEndRegex)
val script = convertToPythonScript(lines)
val correctAnswers = mutableListOf<Any>()
val correctAnswers: MutableList<Any> = []

logger.debug { "$challengeName return type: $returnType script: \n${script.withLineNumbers()}" }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,15 @@ internal object JavaParse {
internal val svmRegex = Regex("""\s*static\s+void\s+main\(""")

private val prefixRegex =
listOf(
[
Regex("""System\.out\.println\("""),
Regex("""ArrayUtils\.arrayPrint\("""),
Regex("""ListUtils\.listPrint\("""),
Regex("""arrayPrint\("""),
Regex("""listPrint\("""),
)
]
private val prefixes =
listOf("System.out.println", "ArrayUtils.arrayPrint", "ListUtils.listPrint", "arrayPrint", "listPrint")
["System.out.println", "ArrayUtils.arrayPrint", "ListUtils.listPrint", "arrayPrint", "listPrint"]

/**
* Derives the return type of a Java challenge function by locating the first `static` method
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -706,11 +706,9 @@ internal object ChallengePage {
val groupName = challenge.groupName
val challengeName = challenge.challengeName

p(classes = TwClasses.EXPERIMENT) {
+"Experiment with this code on "
this@otherLinks.addLink("Gitpod.io", "https://gitpod.io/#${challenge.gitpodUrl}", true)
if (languageType.isKotlin) {
+" or as a "
if (languageType.isKotlin) {
p(classes = TwClasses.EXPERIMENT) {
+"Experiment with this code as a "
this@otherLinks.addLink("Kotlin Playground", pathOf(PLAYGROUND_ROOT, groupName, challengeName), false)
}
}
Expand Down
Loading
Loading