Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added: Explicit API - Strict mode in Kotlin #38

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
5 changes: 5 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.gradle.api.tasks.testing.logging.TestLogEvent
import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode.Strict

plugins {
// Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin.
Expand Down Expand Up @@ -44,6 +45,10 @@ publishing {
}
}

kotlin {
explicitApi = Strict
}

dependencies {
// Use the Kotlin JUnit 5 integration.
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/com/featurevisor/sdk/Bucket.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package com.featurevisor.sdk
import com.goncalossilva.murmurhash.MurmurHash3
import kotlin.math.floor

object Bucket {
internal object Bucket {

private const val HASH_SEED = 1u
private const val MAX_HASH_VALUE = 4294967296 // 2^32
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/com/featurevisor/sdk/Conditions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import com.featurevisor.types.Operator.SEMVER_NOT_EQUALS
import com.featurevisor.types.Operator.STARTS_WITH
import net.swiftzer.semver.SemVer

object Conditions {
internal object Conditions {

fun conditionIsMatched(condition: Plain, context: Context): Boolean {
val (attributeKey, operator, conditionValue) = condition
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/com/featurevisor/sdk/DatafileReader.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import com.featurevisor.types.FeatureKey
import com.featurevisor.types.Segment
import com.featurevisor.types.SegmentKey

class DatafileReader constructor(
internal class DatafileReader constructor(
datafileJson: DatafileContent,
) {

Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/com/featurevisor/sdk/Emitter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.featurevisor.sdk

import com.featurevisor.types.EventName

class Emitter {
internal class Emitter {

private val listeners = mutableMapOf<EventName, (Array<out Any>) -> Unit>()

Expand Down
12 changes: 6 additions & 6 deletions src/main/kotlin/com/featurevisor/sdk/FeaturevisorError.kt
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
package com.featurevisor.sdk

sealed class FeaturevisorError(message: String) : Throwable(message = message) {
public sealed class FeaturevisorError(message: String) : Throwable(message = message) {

/// Thrown when attempting to init Featurevisor instance without passing datafile and datafileUrl.
/// At least one of them is required to init the SDK correctly
object MissingDatafileOptions : FeaturevisorError("Missing data file options")
public object MissingDatafileOptions : FeaturevisorError("Missing data file options")

class FetchingDataFileFailed(val result: String) : FeaturevisorError("Fetching data file failed")
public class FetchingDataFileFailed(public val result: String) : FeaturevisorError("Fetching data file failed")

/// Thrown when receiving unparseable Datafile JSON responses.
/// - Parameters:
/// - data: The data being parsed.
/// - errorMessage: The message from the error which occured during parsing.
class UnparsableJson(val data: String?, errorMessage: String) : FeaturevisorError(errorMessage)
public class UnparsableJson(public val data: String?, errorMessage: String) : FeaturevisorError(errorMessage)

/// Thrown when attempting to construct an invalid URL.
/// - Parameter string: The invalid URL string.
class InvalidUrl(val url: String?) : FeaturevisorError("Invalid URL")
public class InvalidUrl(public val url: String?) : FeaturevisorError("Invalid URL")

object MissingDatafileUrlWhileRefreshing : FeaturevisorError("Missing datafile url need to refresh")
public object MissingDatafileUrlWhileRefreshing : FeaturevisorError("Missing datafile url need to refresh")
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import com.featurevisor.types.EventName.ACTIVATION
import com.featurevisor.types.FeatureKey
import com.featurevisor.types.VariationValue

fun FeaturevisorInstance.activate(featureKey: FeatureKey, context: Context = emptyMap()): VariationValue? {
public fun FeaturevisorInstance.activate(featureKey: FeatureKey, context: Context = emptyMap()): VariationValue? {
val evaluation = evaluateVariation(featureKey, context)
val variationValue = evaluation.variation?.value ?: evaluation.variationValue ?: return null
val finalContext = interceptContext?.invoke(context) ?: context
Expand Down
14 changes: 7 additions & 7 deletions src/main/kotlin/com/featurevisor/sdk/Instance+Evaluation.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromJsonElement
import kotlinx.serialization.json.encodeToJsonElement

enum class EvaluationReason(val value: String) {
public enum class EvaluationReason(public val value: String) {
NOT_FOUND("not_found"),
NO_VARIATIONS("no_variations"),
DISABLED("disabled"),
Expand All @@ -41,7 +41,7 @@ enum class EvaluationReason(val value: String) {
}

@Serializable
data class Evaluation(
public data class Evaluation(
val featureKey: FeatureKey,
val reason: EvaluationReason,
val bucketValue: BucketValue? = null,
Expand All @@ -56,7 +56,7 @@ data class Evaluation(
val variableValue: VariableValue? = null,
val variableSchema: VariableSchema? = null,
) {
fun toDictionary(): Map<String, Any> {
public fun toDictionary(): Map<String, Any> {
val data = try {
val json = Json.encodeToJsonElement(this)
Json.decodeFromJsonElement<Map<String, Any>>(json)
Expand All @@ -68,13 +68,13 @@ data class Evaluation(
}
}

fun FeaturevisorInstance.isEnabled(featureKey: FeatureKey, context: Context = emptyMap()): Boolean {
public fun FeaturevisorInstance.isEnabled(featureKey: FeatureKey, context: Context = emptyMap()): Boolean {
val evaluation = evaluateFlag(featureKey, context)
return evaluation.enabled == true
}

@Suppress("UNREACHABLE_CODE")
fun FeaturevisorInstance.evaluateVariation(featureKey: FeatureKey, context: Context = emptyMap()): Evaluation {
public fun FeaturevisorInstance.evaluateVariation(featureKey: FeatureKey, context: Context = emptyMap()): Evaluation {
var evaluation: Evaluation
try {
val flag = evaluateFlag(featureKey, context)
Expand Down Expand Up @@ -231,7 +231,7 @@ fun FeaturevisorInstance.evaluateVariation(featureKey: FeatureKey, context: Cont


@Suppress("UNREACHABLE_CODE")
fun FeaturevisorInstance.evaluateFlag(featureKey: FeatureKey, context: Context = emptyMap()): Evaluation {
public fun FeaturevisorInstance.evaluateFlag(featureKey: FeatureKey, context: Context = emptyMap()): Evaluation {

var evaluation: Evaluation

Expand Down Expand Up @@ -443,7 +443,7 @@ fun FeaturevisorInstance.evaluateFlag(featureKey: FeatureKey, context: Context =
}

@Suppress("UNREACHABLE_CODE")
fun FeaturevisorInstance.evaluateVariable(
public fun FeaturevisorInstance.evaluateVariable(
featureKey: FeatureKey,
variableKey: VariableKey,
context: Context = emptyMap(),
Expand Down
6 changes: 3 additions & 3 deletions src/main/kotlin/com/featurevisor/sdk/Instance+Feature.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import com.featurevisor.types.Feature
import com.featurevisor.types.Force
import com.featurevisor.types.Traffic

fun FeaturevisorInstance.getFeatureByKey(featureKey: String): Feature? {
public fun FeaturevisorInstance.getFeatureByKey(featureKey: String): Feature? {
return datafileReader.getFeature(featureKey)
}

fun FeaturevisorInstance.getFeature(featureKey: String): Feature?{
public fun FeaturevisorInstance.getFeature(featureKey: String): Feature?{
return datafileReader.getFeature(featureKey)
}

Expand Down Expand Up @@ -58,7 +58,7 @@ internal fun FeaturevisorInstance.getMatchedAllocation(
}
}

data class MatchedTrafficAndAllocation(
internal data class MatchedTrafficAndAllocation(
val matchedTraffic: Traffic?,
val matchedAllocation: Allocation?,
)
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/com/featurevisor/sdk/Instance+Fetch.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ private fun fetchDatafileContentFromUrl(
}
}

const val BODY_BYTE_COUNT = 1000000L
internal const val BODY_BYTE_COUNT = 1000000L
private inline fun fetch(
request: Request,
crossinline completion: (Result<DatafileContent>) -> Unit,
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/com/featurevisor/sdk/Instance+Refresh.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch

fun FeaturevisorInstance.startRefreshing() = when {
public fun FeaturevisorInstance.startRefreshing(): Unit? = when {
datafileUrl == null -> {
logger?.error("cannot start refreshing since `datafileUrl` is not provided")
throw MissingDatafileUrlWhileRefreshing
Expand All @@ -26,7 +26,7 @@ fun FeaturevisorInstance.startRefreshing() = when {
}
}

fun FeaturevisorInstance.stopRefreshing() {
public fun FeaturevisorInstance.stopRefreshing() {
refreshJob?.cancel()
refreshJob = null
logger?.warn("refreshing has stopped")
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/com/featurevisor/sdk/Instance+Status.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.featurevisor.sdk

data class Statuses(var ready: Boolean, var refreshInProgress: Boolean)
internal data class Statuses(var ready: Boolean, var refreshInProgress: Boolean)

internal fun FeaturevisorInstance.isReady(): Boolean {
return statuses.ready
Expand Down
16 changes: 8 additions & 8 deletions src/main/kotlin/com/featurevisor/sdk/Instance+Variable.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromJsonElement
import kotlinx.serialization.json.encodeToJsonElement

fun FeaturevisorInstance.getVariable(
public fun FeaturevisorInstance.getVariable(
featureKey: FeatureKey,
variableKey: VariableKey,
context: Context = emptyMap(),
Expand All @@ -30,47 +30,47 @@ fun FeaturevisorInstance.getVariable(
return evaluation.variableValue
}

fun FeaturevisorInstance.getVariableBoolean(
public fun FeaturevisorInstance.getVariableBoolean(
featureKey: FeatureKey,
variableKey: VariableKey,
context: Context,
): Boolean? {
return (getVariable(featureKey, variableKey, context) as? BooleanValue)?.value
}

fun FeaturevisorInstance.getVariableString(
public fun FeaturevisorInstance.getVariableString(
featureKey: FeatureKey,
variableKey: VariableKey,
context: Context,
): String? {
return (getVariable(featureKey, variableKey, context) as? StringValue)?.value
}

fun FeaturevisorInstance.getVariableInteger(
public fun FeaturevisorInstance.getVariableInteger(
featureKey: FeatureKey,
variableKey: VariableKey,
context: Context,
): Int? {
return (getVariable(featureKey, variableKey, context) as? IntValue)?.value
}

fun FeaturevisorInstance.getVariableDouble(
public fun FeaturevisorInstance.getVariableDouble(
featureKey: FeatureKey,
variableKey: VariableKey,
context: Context,
): Double? {
return (getVariable(featureKey, variableKey, context) as? DoubleValue)?.value
}

fun FeaturevisorInstance.getVariableArray(
public fun FeaturevisorInstance.getVariableArray(
featureKey: FeatureKey,
variableKey: VariableKey,
context: Context,
): List<String>? {
return (getVariable(featureKey, variableKey, context) as? ArrayValue)?.values
}

inline fun <reified T : Any> FeaturevisorInstance.getVariableObject(
public inline fun <reified T : Any> FeaturevisorInstance.getVariableObject(
featureKey: FeatureKey,
variableKey: VariableKey,
context: Context,
Expand All @@ -84,7 +84,7 @@ inline fun <reified T : Any> FeaturevisorInstance.getVariableObject(
}
}

inline fun <reified T : Any> FeaturevisorInstance.getVariableJSON(
public inline fun <reified T : Any> FeaturevisorInstance.getVariableJSON(
featureKey: FeatureKey,
variableKey: VariableKey,
context: Context,
Expand Down
28 changes: 14 additions & 14 deletions src/main/kotlin/com/featurevisor/sdk/Instance.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,27 @@ import kotlinx.coroutines.Job
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json

typealias ConfigureBucketKey = (Feature, Context, BucketKey) -> BucketKey
typealias ConfigureBucketValue = (Feature, Context, BucketValue) -> BucketValue
typealias InterceptContext = (Context) -> Context
typealias DatafileFetchHandler = (datafileUrl: String) -> Result<DatafileContent>
internal typealias ConfigureBucketKey = (Feature, Context, BucketKey) -> BucketKey
internal typealias ConfigureBucketValue = (Feature, Context, BucketValue) -> BucketValue
internal typealias InterceptContext = (Context) -> Context
internal typealias DatafileFetchHandler = (datafileUrl: String) -> Result<DatafileContent>

var emptyDatafile = DatafileContent(
internal var emptyDatafile = DatafileContent(
schemaVersion = "1",
revision = "unknown",
attributes = emptyList(),
segments = emptyList(),
features = emptyList(),
)

class FeaturevisorInstance private constructor(options: InstanceOptions) {
public class FeaturevisorInstance private constructor(options: InstanceOptions) {

companion object {
fun createInstance(options: InstanceOptions): FeaturevisorInstance {
public companion object {
public fun createInstance(options: InstanceOptions): FeaturevisorInstance {
return FeaturevisorInstance(options)
}

var companionLogger: Logger? = null
public var companionLogger: Logger? = null
}

private val on: (EventName, Listener) -> Unit
Expand Down Expand Up @@ -118,11 +118,11 @@ class FeaturevisorInstance private constructor(options: InstanceOptions) {
}
}

fun setLogLevels(levels: List<Logger.LogLevel>) {
public fun setLogLevels(levels: List<Logger.LogLevel>) {
this.logger?.setLevels(levels)
}

fun setDatafile(datafileJSON: String) {
public fun setDatafile(datafileJSON: String) {
val data = datafileJSON.toByteArray(Charsets.UTF_8)
try {
val datafileContent = Json.decodeFromString<DatafileContent>(String(data))
Expand All @@ -132,15 +132,15 @@ class FeaturevisorInstance private constructor(options: InstanceOptions) {
}
}

fun setDatafile(datafileContent: DatafileContent) {
public fun setDatafile(datafileContent: DatafileContent) {
datafileReader = DatafileReader(datafileJson = datafileContent)
}

fun setStickyFeatures(stickyFeatures: StickyFeatures?) {
public fun setStickyFeatures(stickyFeatures: StickyFeatures?) {
this.stickyFeatures = stickyFeatures
}

fun getRevision(): String {
public fun getRevision(): String {
return datafileReader.getRevision()
}
}
6 changes: 3 additions & 3 deletions src/main/kotlin/com/featurevisor/sdk/InstanceOptions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import com.featurevisor.types.DatafileContent
import com.featurevisor.types.InitialFeatures
import com.featurevisor.types.StickyFeatures

typealias Listener = (Array<out Any>) -> Unit
public typealias Listener = (Array<out Any>) -> Unit

data class InstanceOptions(
public data class InstanceOptions(
val bucketKeySeparator: String = defaultBucketKeySeparator,
val configureBucketKey: ConfigureBucketKey? = null,
val configureBucketValue: ConfigureBucketValue? = null,
Expand All @@ -24,7 +24,7 @@ data class InstanceOptions(
val refreshInterval: Long? = null, // seconds
val stickyFeatures: StickyFeatures? = null,
) {
companion object {
internal companion object {
private const val defaultBucketKeySeparator = "."
}
}
Loading
Loading