UNPKG

@kform/core

Version:

JavaScript bindings for KForm.

1 lines 848 kB
{"version":3,"sources":["../../../../../../../kform-core/src/commonMain/kotlin/AbsolutePath.kt","../../../../../../../kform-core/src/commonMain/kotlin/Path.kt","common/src/generated/_Arrays.kt","js/src/kotlin/collectionJs.kt","src/kotlin/text/StringBuilder.kt","src/kotlin/util/Standard.kt","common/src/generated/_Collections.kt","../../../../../../../kform-core/src/commonMain/kotlin/Computations.kt","src/kotlin/util/Preconditions.kt","src/kotlin/collections/Maps.kt","../../../../../../../kform-core/src/commonMain/kotlin/ComputedValues.kt","../../../../../../../kform-core/src/commonMain/kotlin/Events.kt","../../../../../../../kform-core/src/commonMain/kotlin/Exceptions.kt","../../../../../../../kform-core/src/commonMain/kotlin/FormManager.kt","../../../../../../../kform-core/src/commonMain/kotlin/FormUtils.kt","../../../../../../../kform-core/src/commonMain/kotlin/Info.kt","src/kotlin/text/Char.kt","src/kotlin/text/Strings.kt","src/kotlin/collections/Collections.kt","src/kotlin/collections/MutableCollections.kt","../../../../../../../kform-core/src/commonMain/kotlin/PathFragments.kt","../../../../../../../kform-core/src/commonMain/kotlin/Schemas.kt","../../../../../../../kform-core/src/commonMain/kotlin/TypeInfo.kt","../../../../../../../kform-core/src/commonMain/kotlin/ValidationIssues.kt","common/src/generated/_Maps.kt","src/kotlin/collections/Sets.kt","../../../../../../../kform-core/src/commonMain/kotlin/Validations.kt","../../../../../../../kform-core/src/commonMain/kotlin/collections/PathMultimap.kt","../../../../../../../kform-core/src/commonMain/kotlin/collections/PathTrie.kt","common/src/generated/_Sequences.kt","../../../../../../../kform-core/src/commonMain/kotlin/datatypes/File.kt","../../../../../../../kform-core/src/commonMain/kotlin/datatypes/Table.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/ActionAccesses.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/ActionManager.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/ComputationUtils.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/ComputedValueDependencies.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/Exceptions.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/ExternalIssuesDependencies.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/FormManagerEventsBus.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/InfoImpl.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/SchemaEventsCallbackBus.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/SchemaEventsNoOpBus.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/StateImpl.kt","js/builtins/Library.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/Symbol.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/ValidationDaemon.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/ValidationDependencies.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/WriteValues.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/AddExternalIssuesAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/FormManagerAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/ValueStateAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/ComputeValuesAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/WriteValueStateAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/GetAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/ReadValueStateAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/GetCloneAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/GetExternalContextAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/HasAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/InfoAction.kt","../../../../../../../../../../agent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/common/src/flow/internal/SafeCollector.common.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/InvalidateValidationsAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/IsDirtyAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/IsTouchedAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/RemoveAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/RemoveCachedIssuesAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/RemoveDependingExternalIssuesAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/RemoveExternalContextAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/WriteExternalContextAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/RemoveExternalIssuesAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/SetAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/SetDirtyAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/SetExternalContextAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/SetPristineAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/SetTouchedAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/SetUntouchedAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/StartValidationDaemonAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/StopValidationDaemonAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/UpdateDescendantsDisplayingIssuesAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/UpdateStatefulComputedValuesStateAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/UpdateStatefulValidationsStateAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/ValidateAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/actions/ValueInfoAction.kt","../../../../../../../kform-core/src/commonMain/kotlin/schemas/AbstractCollectionSchema.kt","../../../../../../../kform-core/src/commonMain/kotlin/schemas/AbstractSimpleSchema.kt","../../../../../../../kform-core/src/commonMain/kotlin/schemas/BigDecimalSchema.kt","../../../../../../../kform-core/src/commonMain/kotlin/schemas/BigIntegerSchema.kt","../../../../../../../kform-core/src/commonMain/kotlin/schemas/BooleanSchema.kt","../../../../../../../kform-core/src/commonMain/kotlin/schemas/ClassSchema.kt","../../../../../../../kform-core/src/commonMain/kotlin/schemas/DoubleSchema.kt","../../../../../../../kform-core/src/commonMain/kotlin/schemas/FileSchema.kt","../../../../../../../kform-core/src/commonMain/kotlin/schemas/ListSchema.kt","../../../../../../../kform-core/src/commonMain/kotlin/schemas/NullableSchema.kt","../../../../../../../kform-core/src/commonMain/kotlin/schemas/StringSchema.kt","../../../../../../../kform-core/src/commonMain/kotlin/schemas/TableSchema.kt","../../../../../../../kform-core/src/commonMain/kotlin/util/TablePathUtils.kt","../../../../../../../kform-core/src/commonMain/kotlin/validations/AcceptedFileTypes.kt","js/src/kotlin/text/stringJs.kt","../../../../../../../kform-core/src/commonMain/kotlin/validations/AllowedValues.kt","../../../../../../../kform-core/src/commonMain/kotlin/validations/ComparableBounds.kt","../../../../../../../kform-core/src/commonMain/kotlin/validations/LengthBounds.kt","../../../../../../../kform-core/src/commonMain/kotlin/validations/Patterns.kt","../../../../../../../kform-core/src/commonMain/kotlin/validations/RequiredValues.kt","../../../../../../../kform-core/src/commonMain/kotlin/validations/Scale.kt","../../../../../../../kform-core/src/commonMain/kotlin/validations/SizeBounds.kt","../../../../../../../kform-core/src/commonMain/kotlin/validations/UniqueItems.kt","js/src/kotlin/math.kt","../../../../../../../kform-core/src/commonMain/kotlin/Status.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/KTypeToString.kt","../../../../../../../kform-core/src/commonMain/kotlin/internal/PathUtils.kt","../../../../../../../kform-core/src/commonMain/kotlin/schemas/util/SchemaRestrictions.kt","../../../../../../../kform-core/src/commonMain/kotlin/util/SchemaPathUtils.kt"],"sourcesContent":["package io.kform\n\nimport kotlin.js.JsName\nimport kotlin.jvm.JvmField\nimport kotlin.jvm.JvmOverloads\nimport kotlin.math.min\nimport kotlinx.serialization.KSerializer\nimport kotlinx.serialization.Serializable\nimport kotlinx.serialization.descriptors.PrimitiveKind\nimport kotlinx.serialization.descriptors.PrimitiveSerialDescriptor\nimport kotlinx.serialization.descriptors.SerialDescriptor\nimport kotlinx.serialization.encoding.Decoder\nimport kotlinx.serialization.encoding.Encoder\n\n/**\n * Representation of an absolute path as a subtype of [Path] and as a list of absolute path\n * fragments. Absolute paths are always \"resolved\" (i.e. they contain no unnecessary fragments such\n * as current path fragments or consecutive recursive wildcard fragments).\n *\n * Absolute paths represent locations of data from a root location: e.g. the location of a value\n * within a value where the outer value is seen as the \"root\" value.\n *\n * Unlike regular paths, the root fragment is always implicit in absolute paths and is not visible\n * in the list of fragments.\n */\n@JsName(\"AbsolutePathKt\")\n@Serializable(with = AbsolutePath.Serializer::class)\npublic class AbsolutePath\nprivate constructor(fragments: List<PathFragment>, needsResolving: Boolean) :\n Path(if (needsResolving) resolveImpl(listOf(PathFragment.Root), fragments) else fragments) {\n // The [realFragments] have a [PathFragment.RootFragment] at index `0`\n @Suppress(\"UNCHECKED_CAST\")\n override val fragments: List<AbsolutePathFragment>\n get() = realFragments.drop(1) as List<AbsolutePathFragment>\n\n /** Size of the path (number of fragments it has). */\n public val size: Int\n get() = realFragments.size - 1\n\n /** Whether this path represents the root path. */\n public val isRoot: Boolean\n get() = realFragments.size == 1\n\n /** Last fragment of this path or `null` for the root path. */\n public val lastFragment: AbsolutePathFragment?\n get() = if (isRoot) null else realFragments.last() as AbsolutePathFragment\n\n /** Creates an absolute path from a list of [fragments]. */\n @JvmOverloads\n public constructor(\n fragments: List<AbsolutePathFragment> = emptyList()\n ) : this(\n // Remove consecutive recursive wildcard fragments\n listOf(PathFragment.Root) +\n fragments.filterIndexed { i, fragment ->\n fragment != AbsolutePathFragment.RecursiveWildcard ||\n fragments.getOrNull(i + 1) != AbsolutePathFragment.RecursiveWildcard\n },\n needsResolving = false,\n )\n\n /**\n * Creates an absolute path from a path [path]. The path will be resolved against the root path.\n */\n public constructor(\n path: Path\n ) : this(path.realFragments, needsResolving = path !is AbsolutePath)\n\n /**\n * Creates an absolute path from a string representation of a path [stringPath]. The string will\n * first be converted into a path and then resolved against the root path.\n */\n public constructor(stringPath: String) : this(Path(stringPath))\n\n /**\n * Returns the fragment of this path with index [index].\n *\n * @throws IndexOutOfBoundsException When an out of bounds [index] is provided.\n */\n public override fun fragment(index: Int): AbsolutePathFragment =\n realFragments[index + 1] as AbsolutePathFragment // Skip root fragment\n\n /**\n * Returns the fragment of this path with index [index].\n *\n * @throws IndexOutOfBoundsException When an out of bounds [index] is provided.\n */\n public override operator fun get(index: Int): AbsolutePathFragment = fragment(index)\n\n /** Returns whether this path has at least one non-recursive wildcard. */\n public fun hasWildcard(): Boolean =\n realFragments.any { fragment -> fragment is AbsolutePathFragment.Wildcard }\n\n /** Returns whether this path has at least one recursive wildcard. */\n public fun hasRecursiveWildcard(): Boolean =\n realFragments.any { fragment -> fragment is AbsolutePathFragment.RecursiveWildcard }\n\n /** Returns whether this path has at least one wildcard (either recursive or not). */\n public fun hasAnyWildcard(): Boolean =\n realFragments.any { fragment ->\n fragment is AbsolutePathFragment.Wildcard ||\n fragment is AbsolutePathFragment.RecursiveWildcard\n }\n\n /**\n * Returns an absolute path representing the parent of this path. Equivalent to `resolve(\"..\")`.\n *\n * Note that the parent of the root path is the root path itself.\n */\n override fun parent(): AbsolutePath =\n AbsolutePath(parentImpl(realFragments), needsResolving = false)\n\n /** Returns the absolute path resulting from appending [fragments] to this path. */\n public fun append(vararg fragments: AbsolutePathFragment): AbsolutePath =\n AbsolutePath(\n // Remove consecutive recursive wildcard fragments\n realFragments +\n fragments.filterIndexed { i, fragment ->\n fragment != AbsolutePathFragment.RecursiveWildcard ||\n (if (i == 0) realFragments.last() else fragments[i - 1]) !=\n AbsolutePathFragment.RecursiveWildcard\n },\n needsResolving = false,\n )\n\n /** Returns the absolute path resulting from appending [fragment] to this path. */\n public operator fun plus(fragment: AbsolutePathFragment): AbsolutePath = append(fragment)\n\n /** Returns the absolute path resulting from resolving a list of [paths] against this path. */\n override fun resolve(vararg paths: Path): AbsolutePath =\n when {\n paths.isEmpty() -> this\n // Optimise case where last path (in most cases the only path) is an absolute path, in\n // which case no resolving is needed\n paths.last() is AbsolutePath -> paths.last() as AbsolutePath\n else ->\n AbsolutePath(\n resolveImpl(\n realFragments,\n *paths.map { path -> path.realFragments }.toTypedArray(),\n ),\n needsResolving = false,\n )\n }\n\n /**\n * Returns the absolute path resulting from resolving a list of paths in string notation\n * [stringPaths] against this path.\n */\n override fun resolve(vararg stringPaths: String): AbsolutePath =\n resolve(*stringPaths.map { str -> Path(str) }.toTypedArray())\n\n /**\n * Returns the absolute path resulting from resolving [path] against this path. Equivalent to\n * `resolve(path)`.\n */\n public override operator fun plus(path: Path): AbsolutePath = resolve(path)\n\n /**\n * Returns the absolute path resulting from resolving the path in string notation [stringPath]\n * against this path. Equivalent to `resolve(stringPath)`.\n */\n public override operator fun plus(stringPath: String): AbsolutePath = resolve(stringPath)\n\n /**\n * Returns whether this path matches with [path]. Note that [path] will be converted to an\n * [absolute path][AbsolutePath] when it isn't one.\n *\n * For the purpose of matching, a [wildcard fragment][AbsolutePathFragment.Wildcard] matches\n * against any other fragment and a [recursive wildcard fragment]\n * [AbsolutePathFragment.RecursiveWildcard] matches against zero or more any other fragments.\n * Non-wildcard fragments match against each other on a basis of equality (`==`).\n */\n public fun matches(path: Path): Boolean =\n matchesImpl(fragments, path.toAbsolutePath().fragments)\n\n /**\n * Returns whether this path contains [path]. Note that [path] will be converted to an\n * [absolute path][AbsolutePath] when it isn't one.\n *\n * We say that a path `p1` contains a path `p2` when all paths that [match][matches] against\n * `p2` also [match][matches] against `p1`. I.e. `p1.contains(p2) == true` iff there does\n * **not** exist a path `p3` such that `p3.matches(p2) == true` and `p3.matches(p1) == false`.\n */\n public operator fun contains(path: Path): Boolean =\n containsImpl(fragments, path.toAbsolutePath().fragments)\n\n /**\n * Returns a relative path representing this path, but relative to [path]. Note that [path] will\n * be converted to an [absolute path][AbsolutePath] when it isn't one.\n *\n * In other words, if `relPath1 = path1.relativeTo(path2)`, then `path2.resolve(relPath1) ==\n * path1`.\n */\n public fun relativeTo(path: Path): Path =\n Path(relativeImpl(path.toAbsolutePath().fragments, fragments))\n\n override fun equals(other: Any?): Boolean =\n when {\n this === other -> true\n other !is Path -> false\n other is AbsolutePath -> realFragments == other.realFragments\n else -> realFragments == other.resolve().realFragments\n }\n\n override fun hashCode(): Int = realFragments.hashCode()\n\n override operator fun iterator(): Iterator<AbsolutePathFragment> = fragments.iterator()\n\n public companion object {\n // Common paths:\n /** Absolute root path (`\"/\"`). */\n @JvmField public val ROOT: AbsolutePath = AbsolutePath()\n\n /** Absolute path that matches all other paths (`\"/\u2217\u2217\"`). */\n @JvmField\n public val MATCH_ALL: AbsolutePath =\n AbsolutePath(listOf(AbsolutePathFragment.RecursiveWildcard))\n\n /**\n * Implementation of [matches]. Returns whether two lists of fragments match.\n *\n * The algorithm recursively matches the two lists taking into consideration recursive\n * wildcard fragments. It implements the following pseudo-algorithm:\n * ```\n * matches l1 l2 = match (l1, l2):\n * | ([], []) -> true\n * | ([**], []) -> true\n * | ([], [**]) -> true\n * | (**::t1, h2::t2) -> matches(t1, h2::t2) || matches(**::t1, t2)\n * | (h1::t1, **::t2) -> matches(h1::t1, t2) || matches(t1, **::t2)\n * | (*::t1, _::t2) -> matches(t1, t2)\n * | (_::t1, *::t2) -> matches(t1, t2)\n * | (h::t1, h::t2) -> matches(t1, t2)\n * | _ -> false\n * ```\n *\n * @param f1 First list of fragments.\n * @param f2 Second list of fragments.\n * @param i1 Index of `f1`'s head. `l1` in the above pseudocode is represented by\n * `f1.slice(i1)`.\n * @param i2 Index of `f2`'s head. `l2` in the above pseudocode is represented by\n * `f2.slice(i2)`.\n */\n private fun matchesImpl(\n f1: List<AbsolutePathFragment>,\n f2: List<AbsolutePathFragment>,\n i1: Int = 0,\n i2: Int = 0,\n ): Boolean {\n // List sizes\n val s1 = f1.size - i1\n val s2 = f2.size - i2\n\n // List heads\n val h1 = f1.getOrNull(i1)\n val h2 = f2.getOrNull(i2)\n\n // Base cases:\n // | ([], []) -> true\n // | ([**], []) -> true\n // | ([], [**]) -> true\n if (\n (s1 == 0 && s2 == 0) ||\n (s1 == 1 && s2 == 0 && h1 is AbsolutePathFragment.RecursiveWildcard) ||\n (s1 == 0 && s2 == 1 && h2 is AbsolutePathFragment.RecursiveWildcard)\n ) {\n return true\n }\n\n // Cases where both lists have at least 1 element:\n if (s1 > 0 && s2 > 0) {\n // Recursive wildcard cases:\n // | (**::t1, h2::t2) -> matches(t1, h2::t2) || matches(**::t1, t2)\n // | (h1::t1, **::t2) -> matches(h1::t1, t2) || matches(t1, **::t2)\n if (\n h1 is AbsolutePathFragment.RecursiveWildcard ||\n h2 is AbsolutePathFragment.RecursiveWildcard\n ) {\n return matchesImpl(f1, f2, i1 + 1, i2) || matchesImpl(f1, f2, i1, i2 + 1)\n }\n\n // Other cases:\n // | (*::t1, _::t2) -> matches(t1, t2)\n // | (_::t1, *::t2) -> matches(t1, t2)\n // | (h::t1, h::t2) -> matches(t1, t2)\n if (\n h1 is AbsolutePathFragment.Wildcard ||\n h2 is AbsolutePathFragment.Wildcard ||\n h1 == h2\n ) {\n return matchesImpl(f1, f2, i1 + 1, i2 + 1)\n }\n }\n\n // _ -> false\n return false\n }\n\n /**\n * Implementation of [contains]. Returns whether the first list of fragments contains the\n * second one.\n *\n * The algorithm recursively checks whether one list contains the other taking into\n * consideration recursive wildcard fragments. It implements the following pseudo-algorithm:\n * ```\n * contains l1 l2 = match (l1, l2):\n * | ([], []) -> true\n * | ([**], _) -> true\n * | (**::t1, h2::t2) -> contains(t1, h2::t2) || contains(**::t1, t2)\n * | (*::t1, h2::t2) -> h2 != ** && contains(t1, t2)\n * | (h::t1, h::t2) -> contains(t1, t2)\n * | _ -> false\n * ```\n *\n * @param f1 First list of fragments.\n * @param f2 Second list of fragments.\n * @param i1 Index of `f1`'s head. `l1` in the above pseudocode is represented by\n * `f1.slice(i1)`.\n * @param i2 Index of `f2`'s head. `l2` in the above pseudocode is represented by\n * `f2.slice(i2)`.\n */\n private fun containsImpl(\n f1: List<AbsolutePathFragment>,\n f2: List<AbsolutePathFragment>,\n i1: Int = 0,\n i2: Int = 0,\n ): Boolean {\n // List sizes\n val s1 = f1.size - i1\n val s2 = f2.size - i2\n\n // List heads\n val h1 = f1.getOrNull(i1)\n val h2 = f2.getOrNull(i2)\n\n // Base cases:\n // | ([], []) -> true\n // | ([**], _) -> true\n if ((s1 == 0 && s2 == 0) || (s1 == 1 && h1 is AbsolutePathFragment.RecursiveWildcard)) {\n return true\n }\n\n // Cases where both lists have at least 1 element:\n if (s1 > 0 && s2 > 0) {\n // Recursive wildcard case:\n // | (**::t1, h2::t2) -> contains(**::t1, t2) || contains(t1, h2::t2)\n if (h1 is AbsolutePathFragment.RecursiveWildcard) {\n return containsImpl(f1, f2, i1 + 1, i2) || containsImpl(f1, f2, i1, i2 + 1)\n }\n\n // Other cases:\n // | (*::t1, h2::t2) -> h2 != ** && contains(t1, t2)\n // | (h::t1, h::t2) -> h != - && contains(t1, t2)\n if (\n (h1 is AbsolutePathFragment.Wildcard &&\n h2 !is AbsolutePathFragment.RecursiveWildcard) || h1 == h2\n ) {\n return containsImpl(f1, f2, i1 + 1, i2 + 1)\n }\n }\n\n // _ -> false\n return false\n }\n }\n\n /** Returns the relative path from [from] to [to]. Used to implement [relativeTo]. */\n private fun relativeImpl(\n from: List<AbsolutePathFragment>,\n to: List<AbsolutePathFragment>,\n ): List<PathFragment> {\n val result = mutableListOf<PathFragment>()\n val size = min(from.size, to.size)\n var samePartsSize = size\n for (i in 0 until size) {\n if (from[i] != to[i]) {\n samePartsSize = i\n break\n }\n }\n\n for (i in samePartsSize until from.size) {\n result += PathFragment.ParentPath\n }\n result += (to.slice(samePartsSize until to.size))\n return result\n }\n\n /** Absolute path serialiser, serialising absolute paths as strings. */\n public object Serializer : KSerializer<AbsolutePath> {\n override val descriptor: SerialDescriptor =\n PrimitiveSerialDescriptor(\"io.kform.AbsolutePath\", PrimitiveKind.STRING)\n\n override fun serialize(encoder: Encoder, value: AbsolutePath): Unit =\n encoder.encodeString(value.toString())\n\n override fun deserialize(decoder: Decoder): AbsolutePath =\n AbsolutePath(decoder.decodeString())\n }\n}\n","@file:JvmName(\"Paths\")\n\npackage io.kform\n\nimport kotlin.js.JsName\nimport kotlin.jvm.JvmField\nimport kotlin.jvm.JvmName\nimport kotlin.jvm.JvmStatic\nimport kotlin.math.min\nimport kotlinx.serialization.KSerializer\nimport kotlinx.serialization.Serializable\nimport kotlinx.serialization.descriptors.PrimitiveKind\nimport kotlinx.serialization.descriptors.PrimitiveSerialDescriptor\nimport kotlinx.serialization.descriptors.SerialDescriptor\nimport kotlinx.serialization.encoding.Decoder\nimport kotlinx.serialization.encoding.Encoder\n\n/**\n * Typealias used to represent a type where either a [Path] or a [String] (representing a path) are\n * accepted.\n */\npublic typealias PathOrString = Any\n\n/**\n * Representation of a path as a list of path [fragments].\n *\n * Paths represent locations of data, possibly relatively to other locations: e.g. the location of a\n * value relative to the location of another value. They can also represent locations of data from\n * the root when they contain a root fragment.\n */\n@JsName(\"PathKt\")\n@Serializable(with = Path.Serializer::class)\npublic open class Path(fragments: List<PathFragment> = emptyList()) {\n /**\n * Internal list of \"real\" fragments. For the generic [Path], this list is the same as the\n * public [fragments] one, however, [AbsolutePath] hides their internal representation (it hides\n * its first \"root fragment\") and the two lists differ.\n */\n internal val realFragments: List<PathFragment> = ArrayList(fragments)\n\n /** List of fragments representing this path. */\n public open val fragments: List<PathFragment>\n get() = realFragments\n\n /** Creates a path from its string notation. E.g. `\"./path/to/somewhere\"`. */\n public constructor(stringPath: String) : this(parse(stringPath))\n\n /**\n * Returns the fragment of this path with index [index].\n *\n * @throws IndexOutOfBoundsException When an out of bounds [index] is provided.\n */\n public open fun fragment(index: Int): PathFragment = realFragments[index]\n\n /**\n * Returns the fragment of this path with index [index].\n *\n * @throws IndexOutOfBoundsException When an out of bounds [index] is provided.\n */\n public open operator fun get(index: Int): PathFragment = fragment(index)\n\n /**\n * Returns a new path representing the parent of this path.\n *\n * Note that the parent of the root path is the root path itself.\n */\n public open fun parent(): Path = Path(parentImpl(realFragments))\n\n /** Returns the path resulting from appending [fragments] to this path. */\n public fun append(vararg fragments: PathFragment): Path = Path(realFragments + fragments)\n\n /**\n * Returns the path resulting from appending [fragment] to this path. Equivalent to\n * `append(fragment)`.\n */\n public operator fun plus(fragment: PathFragment): Path = append(fragment)\n\n /** Returns the path resulting from joining [paths] together with this path. */\n public fun join(vararg paths: Path): Path =\n Path(joinImpl(realFragments, *paths.map { path -> path.realFragments }.toTypedArray()))\n\n /**\n * Returns the path resulting from joining the provided paths in string notation [stringPaths]\n * together with this path.\n */\n public fun join(vararg stringPaths: String): Path =\n join(*stringPaths.map { str -> Path(str) }.toTypedArray())\n\n /**\n * Returns the path resulting from joining [path] together with this path. Equivalent to\n * `join(path)`.\n */\n public open operator fun plus(path: Path): Path = join(path)\n\n /**\n * Returns the path resulting from joining the path in string notation [stringPath] together\n * with this path. Equivalent to `join(stringPath)`.\n */\n public open operator fun plus(stringPath: String): Path = join(stringPath)\n\n /**\n * Returns the result of resolving this path. Resolving the path removes unnecessary fragments\n * such as the [current path fragment][PathFragment.CurrentPath].\n */\n public fun resolve(): Path = Path(resolveImpl(realFragments))\n\n /** Returns the path resulting from resolving a list of [paths] against this path. */\n public open fun resolve(vararg paths: Path): Path =\n Path(resolveImpl(realFragments, *paths.map { path -> path.realFragments }.toTypedArray()))\n\n /**\n * Returns the path resulting from resolving a list of paths in string notation [stringPaths]\n * against this path.\n */\n public open fun resolve(vararg stringPaths: String): Path =\n resolve(*stringPaths.map { str -> Path(str) }.toTypedArray())\n\n /**\n * Returns whether this path equals [other].\n *\n * Two paths are equal when they both resolve to paths with the exact same fragments.\n */\n override fun equals(other: Any?): Boolean =\n when {\n this === other -> true\n other !is Path -> false\n else -> resolve().realFragments == other.resolve().realFragments\n }\n\n /** Returns the hash code for this path. */\n override fun hashCode(): Int = resolve().realFragments.hashCode()\n\n /** Returns the path in string notation. */\n override fun toString(): String = buildString {\n for ((i, fragment) in realFragments.withIndex()) {\n if (fragment is PathFragment.Root) {\n clear()\n append(SEPARATOR_CHARACTER)\n } else {\n append(fragmentToString(fragment))\n // Add a trailing slash only when the last fragment is an empty id\n if (\n i < realFragments.size - 1 ||\n (fragment is AbsolutePathFragment.Id && fragment.id == \"\")\n ) {\n append(SEPARATOR_CHARACTER)\n }\n }\n }\n }\n\n /** Returns an iterator over the path's fragments. */\n public open operator fun iterator(): Iterator<PathFragment> = realFragments.iterator()\n\n public companion object {\n // Common paths:\n /** Path representing the current path (`\".\"`). */\n @JvmField public val CURRENT: Path = Path()\n\n /** Path representing the current path and all of its descendants (`\"./\u2217\u2217\"`). */\n @JvmField\n public val CURRENT_DEEP: Path = Path(listOf(AbsolutePathFragment.RecursiveWildcard))\n\n /** Path representing the parent path (`\"..\"`). */\n @JvmField public val PARENT: Path = Path(listOf(PathFragment.ParentPath))\n\n /** Path representing the children of a path (`\"./\u2217\"`). */\n @JvmField public val CHILDREN: Path = Path(listOf(AbsolutePathFragment.Wildcard))\n\n /** Path representing the descendants of a path (`\"./\u2217/\u2217\u2217\"`). */\n @JvmField\n public val DESCENDANTS: Path =\n Path(listOf(AbsolutePathFragment.Wildcard, AbsolutePathFragment.RecursiveWildcard))\n\n // Strings/characters to parse paths from strings:\n /**\n * Special fragment string representing the end of a collection. Use `\"~-\"` within a string\n * representation of a path to represent the fragment with id `\"-\"` literally.\n */\n public const val COLLECTION_END_STRING: String = \"-\"\n\n /**\n * Special fragment string representing \"any\" fragment. Use `\"~*\"` within a string\n * representation of a path to represent the fragment with id `\"*\"` literally.\n */\n public const val WILDCARD_STRING: String = \"*\"\n\n /**\n * Special fragment string representing zero or more fragments. Use `\"~**\"` within a string\n * representation of a path to represent the fragment with id `\"**\"` literally.\n */\n public const val RECURSIVE_WILDCARD_STRING: String = \"**\"\n\n /**\n * Special fragment string representing the \"current\" path. Use `\"~.\"` within a string\n * representation of a path to represent the fragment with id `\".\"` literally.\n */\n public const val CURRENT_PATH_STRING: String = \".\"\n\n /**\n * Special fragment string representing the \"parent\" path. Use `\"~..\"` within a string\n * representation of a path to represent the fragment with id `\"..\"` literally.\n */\n public const val PARENT_PATH_STRING: String = \"..\"\n\n /**\n * Character used as part of an escape sequence in the string representation of paths. It\n * may be used to escape the special fragments `\".\"`, `\"..\"`, `\"*\"`, and `\"**\"` with `\"~.\"`,\n * `\"~..\"`, `\"~*\"`, and `\"~**\"` respectively, as well as escape characters such as `\"/\"`,\n * `\"~\"`, `\"{\"`, `\"=\"`, `\";\"`, and `\"}\"`.\n */\n public const val ESCAPE_CHARACTER: Char = '~'\n\n /**\n * Character used to represent the root path in string form, as well as separate fragments,\n * e.g. the path with id fragments `x` and `y` is represented in string form as `\"/x/y\"`\n * whilst the one with no fragments (root) is represented as `\"/\"`.\n */\n public const val SEPARATOR_CHARACTER: Char = '/'\n\n // Regular expressions used to escape fragments when converting a path to\n // its string form\n private val FRAGMENT_ESCAPE_REGEX = Regex(\"([~/])\")\n\n /**\n * Returns [fragment] in string notation (e.g. to be used in the string representation of a\n * path). Id fragments may end up escaped when they would otherwise represent a different\n * fragment.\n */\n @JvmStatic\n public fun fragmentToString(fragment: PathFragment): String {\n return when (fragment) {\n is AbsolutePathFragment.Id -> {\n val id = fragment.id\n // Escape fragments that would have special meanings\n if (\n id == COLLECTION_END_STRING ||\n id == WILDCARD_STRING ||\n id == RECURSIVE_WILDCARD_STRING ||\n id == CURRENT_PATH_STRING ||\n id == PARENT_PATH_STRING\n ) {\n return ESCAPE_CHARACTER + id\n }\n // Escape the escape character and the path separator\n return id.replace(FRAGMENT_ESCAPE_REGEX, \"$ESCAPE_CHARACTER$1\")\n }\n is AbsolutePathFragment.CollectionEnd -> COLLECTION_END_STRING\n is AbsolutePathFragment.Wildcard -> WILDCARD_STRING\n is AbsolutePathFragment.RecursiveWildcard -> RECURSIVE_WILDCARD_STRING\n is PathFragment.Root -> SEPARATOR_CHARACTER.toString()\n is PathFragment.CurrentPath -> CURRENT_PATH_STRING\n is PathFragment.ParentPath -> PARENT_PATH_STRING\n }\n }\n\n /**\n * Returns the list of path fragments represented by a path in string notation [stringPath].\n */\n private fun parse(stringPath: String): List<PathFragment> {\n val fragmentList: MutableList<PathFragment> = mutableListOf()\n var fragmentId = \"\"\n var i = 0\n val l = stringPath.length\n mainLoop@ while (i < l) {\n val c = stringPath[i]\n // Unescape\n if (c == ESCAPE_CHARACTER) {\n fragmentId += stringPath.getOrNull(++i)?.toString() ?: \"\"\n ++i\n continue\n }\n // Handle path separator\n if (c == SEPARATOR_CHARACTER) {\n // Represent an absolute path by setting the first fragment as the\n // root\n if (i == 0) {\n fragmentList += PathFragment.Root\n } else {\n fragmentList += AbsolutePathFragment.Id(fragmentId)\n fragmentId = \"\"\n }\n ++i\n continue\n }\n if (fragmentId == \"\") {\n // Handle special fragments\n for (spFragment in\n listOf(\n PathFragment.CurrentPath,\n PathFragment.ParentPath,\n AbsolutePathFragment.CollectionEnd,\n AbsolutePathFragment.Wildcard,\n AbsolutePathFragment.RecursiveWildcard,\n )) {\n val spStr = fragmentToString(spFragment)\n val spLen = spStr.length\n if (\n stringPath.substring(i, min(i + spLen, l)) == spStr &&\n (i + spLen == l ||\n stringPath.getOrNull(i + spLen) == SEPARATOR_CHARACTER)\n ) {\n fragmentList += spFragment\n i += spLen + 1\n continue@mainLoop\n }\n }\n }\n fragmentId += c\n ++i\n }\n // Ignore trailing slash\n if (fragmentId != \"\") {\n fragmentList += AbsolutePathFragment.Id(fragmentId)\n }\n return fragmentList\n }\n\n /**\n * Implementation of [parent]. Returns the parent of the path represented by the provided\n * path [fragments].\n */\n internal fun parentImpl(fragments: List<PathFragment>): List<PathFragment> =\n when {\n fragments.isEmpty() || fragments.last() == PathFragment.ParentPath ->\n fragments + PathFragment.ParentPath\n fragments.last() == PathFragment.Root -> fragments\n else -> fragments.dropLast(1)\n }\n\n /**\n * Implementation of [join]. Joins all lists of path fragments within an array\n * [fragmentsArray] into a single list of path fragments.\n */\n internal fun joinImpl(vararg fragmentsArray: List<PathFragment>): List<PathFragment> {\n val joined = mutableListOf<PathFragment>()\n for (fragments in fragmentsArray) {\n joined += fragments\n }\n return joined\n }\n\n /**\n * Implementation of [resolve]. Resolves all provided lists of path fragments within an\n * array [fragmentsArray] into a single list of path fragments, removing unnecessary\n * fragments.\n */\n internal fun resolveImpl(vararg fragmentsArray: List<PathFragment>): List<PathFragment> {\n val resolved = mutableListOf<PathFragment>()\n for (fragments in fragmentsArray) {\n for (fragment in fragments) {\n when (fragment) {\n is PathFragment.Root -> {\n resolved.clear()\n resolved += fragment\n }\n is PathFragment.ParentPath ->\n when {\n resolved.isEmpty() || resolved.last() == PathFragment.ParentPath ->\n resolved += fragment\n resolved.last() != PathFragment.Root ->\n resolved.removeAt(resolved.lastIndex)\n }\n is PathFragment.CurrentPath -> {\n /* Always unnecessary. */\n }\n is AbsolutePathFragment.RecursiveWildcard -> {\n // Consecutive recursive wildcards are redundant and may hurt\n // performance of matching algorithms\n if (resolved.last() != fragment) {\n resolved += fragment\n }\n }\n else -> resolved += fragment\n }\n }\n }\n return resolved\n }\n }\n\n /** Path serialiser, serialising paths as strings. */\n public object Serializer : KSerializer<Path> {\n override val descriptor: SerialDescriptor =\n PrimitiveSerialDescriptor(\"io.kform.Path\", PrimitiveKind.STRING)\n\n override fun serialize(encoder: Encoder, value: Path): Unit =\n encoder.encodeString(value.toString())\n\n override fun deserialize(decoder: Decoder): Path = Path(decoder.decodeString())\n }\n}\n\n/** Converts the receiver path into an absolute path, if it wasn't one already. */\npublic fun Path.toAbsolutePath(): AbsolutePath =\n if (this is AbsolutePath) this else AbsolutePath(this)\n\n/**\n * Converts the receiver [Path] or [String] into a path, if it wasn't one already.\n *\n * @throws IllegalArgumentException if the receiver is neither a [Path] nor a [String].\n */\npublic fun PathOrString.toPath(): Path =\n when (this) {\n is Path -> this\n is String -> Path(this)\n else -> throw IllegalArgumentException(\"The receiver must be either a path or a string.\")\n }\n\n/**\n * Converts the receiver [Path] or [String] into an absolute path, if it wasn't one already.\n *\n * @throws IllegalArgumentException if the receiver is neither a [Path] nor a [String].\n */\npublic fun PathOrString.toAbsolutePath(): AbsolutePath =\n when (this) {\n is Path -> this.toAbsolutePath()\n is String -> AbsolutePath(this)\n else -> throw IllegalArgumentException(\"The receiver must be either a path or a string.\")\n }\n",null,null,null,null,null,"package io.kform\n\nimport kotlin.reflect.KType\n\n/** Value information of a validation's dependencies. */\npublic typealias DependenciesValueInfo = Map<String, ValueInfo<*>?>\n\n/**\n * Context provided to a [form manager][FormManager] computation when running it, contains the\n * values of the computation's dependencies at the time the computation was executed.\n */\npublic abstract class ComputationContext(\n private val schema: Schema<*>,\n /** Path at which the computation is occurring. */\n public val path: AbsolutePath,\n /** Path of the schema at which the computation is occurring. */\n public val schemaPath: AbsolutePath,\n /**\n * Value information for each dependency of the computation. Mapping of keys as declared in the\n * [computation dependencies][Computation.dependencies] to their respective value information.\n */\n public val dependenciesInfo: DependenciesValueInfo,\n public val externalContexts: ExternalContexts,\n) {\n // internal var invalidateAfter: Duration? = null\n\n /** Schema at which the computation is occurring. */\n @Suppress(\"UNCHECKED_CAST\") public fun <T> schema(): Schema<T> = schema as Schema<T>\n\n /**\n * Obtains the value information of the dependency with key [dependencyKey] or `null` if the\n * dependency could not be found in the form.\n *\n * @throws IllegalArgumentException If no dependency with key [dependencyKey] was defined in the\n * computation.\n */\n @Suppress(\"UNCHECKED_CAST\")\n public fun <T> dependencyInfoOrNull(dependencyKey: String): ValueInfo<T>? {\n require(dependencyKey in dependenciesInfo) {\n \"No dependency found with key '$dependencyKey'.\"\n }\n return dependenciesInfo[dependencyKey] as ValueInfo<T>?\n }\n\n /**\n * Obtains the value information of the dependency with key [dependencyKey].\n *\n * @throws DependencyNotFoundException If the dependency could not be found in the form.\n * @throws IllegalArgumentException If no dependency with key [dependencyKey] was defined in the\n * computation.\n */\n public fun <T> dependencyInfo(dependencyKey: String): ValueInfo<T> =\n dependencyInfoOrNull(dependencyKey) ?: throw DependencyNotFoundException(dependencyKey)\n\n /**\n * Returns the path of the dependency with key [dependencyKey] or `null` if the dependency could\n * not be found in the form.\n *\n * @throws IllegalArgumentException If no dependency with key [dependencyKey] was defined in the\n * computation.\n */\n public fun dependencyPathOrNull(dependencyKey: String): AbsolutePath? =\n dependencyInfoOrNull<Any?>(dependencyKey)?.path\n\n /**\n * Returns the path of the dependency with key [dependencyKey].\n *\n * @throws DependencyNotFoundException If the dependency could not be found in the form.\n * @throws IllegalArgumentException If no dependency with key [dependencyKey] was defined in the\n * computation.\n */\n public fun dependencyPath(dependencyKey: String): AbsolutePath =\n dependencyInfo<Any?>(dependencyKey).path\n\n /**\n * Returns the schema of the dependency with key [dependencyKey] or `null` if the dependency\n * could not be found in the form.\n *\n * @throws IllegalArgumentException If no dependency with key [dependencyKey] was defined in the\n * computation.\n */\n public fun <T> dependencySchemaOrNull(dependencyKey: String): Schema<T>? =\n dependencyInfoOrNull<T>(dependencyKey)?.schema\n\n /**\n * Returns the schema of the dependency with key [dependencyKey].\n *\n * @throws DependencyNotFoundException If the dependency could not be found in the form.\n * @throws IllegalArgumentException If no dependency with key [dependencyKey] was defined in the\n * computation.\n */\n public fun <T> dependencySchema(dependencyKey: String): Schema<T> =\n dependencyInfo<T>(dependencyKey).schema\n\n /**\n * Returns the value of the dependency with key [dependencyKey] or `null` if the dependency\n * could not be found in the form.\n *\n * @throws IllegalArgumentException If no dependency with key [dependencyKey] was defined in the\n * computation.\n */\n public fun <T> dependencyOrNull(dependencyKey: String): T? =\n dependencyInfoOrNull<T>(dependencyKey)?.value\n\n /**\n * Returns the value of the dependency with key [dependencyKey].\n *\n * @throws DependencyNotFoundException If the dependency could not be found in the form.\n * @throws IllegalArgumentException If no dependency with key [dependencyKey] was defined in the\n * computation.\n */\n public fun <T> dependency(dependencyKey: String): T = dependencyInfo<T>(dependencyKey).value\n\n /**\n * Returns the external context with name [externalContextName] available to the computation or\n * `null` if the external context could not be found.\n *\n * @throws IllegalArgumentException If no external context with key [externalContextName] was\n * defined in the computation.\n */\n @Suppress(\"UNCHECKED_CAST\")\n public fun <T> externalContextOrNull(externalContextName: String): T? {\n require(externalContextName in externalContexts) {\n \"No external context found with name '$externalContextName'.\"\n }\n return externalContexts[externalContextName] as T?\n }\n\n /**\n * Returns the external context with name [externalContextName] available to the computation.\n *\n * @throws ExternalContextNotFoundException If the external context could not be found during\n * the computation.\n * @throws IllegalArgumentException If no external context with key [externalContextName] was\n * defined in the computation.\n */\n public fun <T> externalContext(externalContextName: String): T =\n externalContextOrNull(externalContextName)\n ?: throw ExternalContextNotFoundException(externalContextName)\n\n // TODO: Implement something like this\n // private fun invalidateAfter(d