All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.io.github.optimumcode.json.schema.internal.ReferenceResolver.kt Maven / Gradle / Ivy

There is a newer version: 0.3.0
Show newest version
package io.github.optimumcode.json.schema.internal

import com.eygraber.uri.Uri
import io.github.optimumcode.json.pointer.JsonPointer
import io.github.optimumcode.json.pointer.internal.length

internal interface ReferenceResolver {
  fun ref(refId: RefId): ReferenceHolder

  fun dynamicRef(refId: RefId): ReferenceHolder
}

internal class ReferenceHolder(
  val schemaPath: JsonPointer,
  val assertion: JsonSchemaAssertion,
  val scopeId: Uri,
) {
  operator fun component1(): JsonPointer = schemaPath

  operator fun component2(): JsonSchemaAssertion = assertion

  operator fun component3(): Uri = scopeId
}

internal class DefaultReferenceResolver(
  private val references: Map,
  private val schemaPathsStack: ArrayDeque> = ArrayDeque(),
) : ReferenceResolver {
  override fun ref(refId: RefId): ReferenceHolder {
    val resolvedRef = requireNotNull(references[refId]) { "$refId is not found" }
    return resolvedRef.toRefHolder()
  }

  override fun dynamicRef(refId: RefId): ReferenceHolder {
    val originalRef = requireNotNull(references[refId]) { "$refId is not found" }
    if (!originalRef.dynamic) {
      return originalRef.toRefHolder()
    }

    val fragment = refId.fragment
    val possibleDynamicRefs: MutableList =
      references.asSequence()
        .filter { (id, link) ->
          link.dynamic && id.fragment == fragment && id != refId
        }.map { it.value }.toMutableList()
    possibleDynamicRefs.sortBy { it.schemaPath.length }

    val resolvedDynamicRef =
      schemaPathsStack.firstNotNullOfOrNull { (_, scopeId) ->
        possibleDynamicRefs.firstOrNull { it.scopeId == scopeId }
      }
        // If no outer anchor found use the original ref
        ?: originalRef
    return resolvedDynamicRef.toRefHolder()
  }

  fun pushSchemaPath(
    path: JsonPointer,
    scopeId: Uri,
  ) {
    schemaPathsStack.addLast(path to scopeId)
  }

  fun popSchemaPath() {
    schemaPathsStack.removeLast()
  }

  private fun AssertionWithPath.toRefHolder(): ReferenceHolder =
    ReferenceHolder(
      schemaPath = schemaPath,
      assertion = assertion,
      scopeId = scopeId,
    )
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy