diff --git a/build.gradle.kts b/build.gradle.kts index 983b380cd4..5c03c998e0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -129,6 +129,7 @@ allprojects { Roaster.jdt, Time.lib, Time.javaExtensions, + Time.kotlinExtensions, ToolBase.lib, ToolBase.pluginBase, Validation.javaBundle, diff --git a/buildSrc/src/main/kotlin/PatchGeneratedTemplateString.kt b/buildSrc/src/main/kotlin/PatchGeneratedTemplateString.kt new file mode 100644 index 0000000000..537f33133d --- /dev/null +++ b/buildSrc/src/main/kotlin/PatchGeneratedTemplateString.kt @@ -0,0 +1,83 @@ +/* + * Copyright 2026, TeamDev. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.tasks.TaskProvider +import org.gradle.kotlin.dsl.named +import org.gradle.kotlin.dsl.register + +/** + * Registers a `patchGeneratedTemplateString` task in the project, which replaces + * references to the legacy `io.spine.validation.TemplateString` class (and its + * proto FQN `.spine.validation.TemplateString`) with `io.spine.string.TemplateString` + * in the `generated/` sources. + * + * The task is wired to run after [upstreamTask] (the task that produces the sources + * to be patched) and before `compileJava` and `kspKotlin`. + * + * @param upstreamTask the name of the task whose output should be patched + * (e.g., `generateProto` or `launchSpineCompiler`). + */ +fun Project.patchGeneratedTemplateString(upstreamTask: String): TaskProvider { + val patchTask = tasks.register("patchGeneratedTemplateString") { + dependsOn(upstreamTask) + + val generatedDir = layout.projectDirectory.dir("generated") + inputs.dir(generatedDir).withPropertyName("generatedSources") + outputs.dir(generatedDir).withPropertyName("patchedSources") + + doLast { + val oldClassRef = "io.spine.validation.TemplateString" + val newClassRef = "io.spine.string.TemplateString" + val oldProtoRef = ".spine.validation.TemplateString" + val newProtoRef = ".spine.string.TemplateString" + generatedDir.asFile.walkTopDown() + .filter { it.isFile && (it.extension == "java" || it.extension == "kt") } + .forEach { file -> + val original = file.readText() + if (original.contains(oldClassRef) || original.contains(oldProtoRef)) { + val patched = original + .replace(oldClassRef, newClassRef) + .replace(oldProtoRef, newProtoRef) + file.writeText(patched) + } + } + } + } + + tasks.named("compileJava") { + dependsOn(patchTask) + } + + afterEvaluate { + tasks.named("kspKotlin") { + dependsOn(patchTask) + } + } + + return patchTask +} diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt index 463cbf2b1f..6a0a489cc7 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt @@ -33,8 +33,8 @@ package io.spine.dependency.local */ @Suppress("ConstPropertyName", "unused") object Base { - const val version = "2.0.0-SNAPSHOT.387" - const val versionForBuildScript = "2.0.0-SNAPSHOT.387" + const val version = "2.0.0-SNAPSHOT.389" + const val versionForBuildScript = "2.0.0-SNAPSHOT.389" const val group = Spine.group private const val prefix = "spine" const val libModule = "$prefix-base" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt index 0a52ff7826..6ee3b088ed 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt @@ -46,7 +46,7 @@ object CoreJvmCompiler { /** * The version used to in the build classpath. */ - const val dogfoodingVersion = "2.0.0-SNAPSHOT.063" + const val dogfoodingVersion = "2.0.0-SNAPSHOT.064" /** * The version to be used for integration tests. diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Time.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Time.kt index 4e285fa9d2..e6c184c9cb 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Time.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Time.kt @@ -40,7 +40,7 @@ import io.spine.dependency.Dependency ) object Time : Dependency() { override val group = Spine.group - override val version = "2.0.0-SNAPSHOT.238" + override val version = "2.0.0-SNAPSHOT.240" private const val infix = "spine-time" fun lib(version: String): String = "$group:$infix:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt index 600deeda75..8e39d6aef4 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt @@ -36,7 +36,7 @@ object Validation { /** * The version of the Validation library artifacts. */ - const val version = "2.0.0-SNAPSHOT.415" + const val version = "2.0.0-SNAPSHOT.419" /** * The last version of Validation compatible with ProtoData. diff --git a/buildSrc/src/main/kotlin/module.gradle.kts b/buildSrc/src/main/kotlin/module.gradle.kts index 4596634b75..ad96f75756 100644 --- a/buildSrc/src/main/kotlin/module.gradle.kts +++ b/buildSrc/src/main/kotlin/module.gradle.kts @@ -170,6 +170,8 @@ fun Module.forceConfigurations() { Base.environment, Protobuf.compiler, Time.lib, + Time.javaExtensions, + Time.kotlinExtensions, TestLib.lib, ToolBase.gradlePluginApi, ToolBase.jvmTools, diff --git a/context/build.gradle.kts b/context/build.gradle.kts index 6006bb1c10..ace9fdf86d 100644 --- a/context/build.gradle.kts +++ b/context/build.gradle.kts @@ -65,3 +65,5 @@ afterEvaluate { val launchSpineCompiler by tasks.getting kspKotlin.dependsOn(launchSpineCompiler) } + +patchGeneratedTemplateString(upstreamTask = "launchSpineCompiler") diff --git a/context/src/main/kotlin/io/spine/tools/validation/ErrorPlaceholder.kt b/context/src/main/kotlin/io/spine/tools/validation/ErrorPlaceholder.kt deleted file mode 100644 index 5044d74ae1..0000000000 --- a/context/src/main/kotlin/io/spine/tools/validation/ErrorPlaceholder.kt +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2026, TeamDev. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package io.spine.tools.validation - -/** - * A template placeholder that can be used in error messages. - * - * Enumerates placeholder names that can be used within Protobuf definitions. - * Each validation option declares the supported placeholders. Take a look at - * `options.proto` for examples. - * - * The enum is used by the compiler model and Java renderer when validating and rendering - * built-in option error messages. - */ -@Deprecated( - message = "Please use `io.spine.validation.ErrorPlaceholder` instead.", - replaceWith = ReplaceWith("ErrorPlaceholder", "io.spine.validation.ErrorPlaceholder") -) -public enum class ErrorPlaceholder(public val value: String) { - - // Common placeholders. - FIELD_PATH("field.path"), - FIELD_VALUE("field.value"), - FIELD_TYPE("field.type"), - MESSAGE_TYPE("message.type"), - PARENT_TYPE("parent.type"), - - // Placeholders for the field options. - REGEX_PATTERN("regex.pattern"), - REGEX_MODIFIERS("regex.modifiers"), - GOES_COMPANION("goes.companion"), - FIELD_PROPOSED_VALUE("field.proposed_value"), - FIELD_DUPLICATES("field.duplicates"), - RANGE_VALUE("range.value"), - MAX_VALUE("max.value"), - MAX_OPERATOR("max.operator"), - MIN_VALUE("min.value"), - MIN_OPERATOR("min.operator"), - WHEN_IN("when.in"), - - // Placeholders for the `oneof` options. - GROUP_PATH("group.path"), - - // Placeholder for the message options. - REQUIRE_FIELDS("require.fields"); - - /** - * Converts this placeholder to its runtime counterpart. - */ - public fun toRuntime(): io.spine.validation.ErrorPlaceholder = - io.spine.validation.ErrorPlaceholder.valueOf(name) - - override fun toString(): String = value -} diff --git a/context/src/main/kotlin/io/spine/tools/validation/ErrorPlaceholders.kt b/context/src/main/kotlin/io/spine/tools/validation/Placeholders.kt similarity index 90% rename from context/src/main/kotlin/io/spine/tools/validation/ErrorPlaceholders.kt rename to context/src/main/kotlin/io/spine/tools/validation/Placeholders.kt index ca01a6241f..865ad0e6bf 100644 --- a/context/src/main/kotlin/io/spine/tools/validation/ErrorPlaceholders.kt +++ b/context/src/main/kotlin/io/spine/tools/validation/Placeholders.kt @@ -34,8 +34,8 @@ import io.spine.tools.compiler.ast.OneofGroup import io.spine.tools.compiler.ast.Span import io.spine.tools.compiler.ast.qualifiedName import io.spine.tools.compiler.check -import io.spine.validation.ErrorPlaceholder -import io.spine.validation.extractPlaceholders +import io.spine.string.Placeholder +import io.spine.string.Placeholder.Companion.extractPlaceholders /** * Checks if this [String] contains placeholders that are not present in the given @@ -47,7 +47,7 @@ import io.spine.validation.extractPlaceholders * @param option The name of the option with which the message template was specified. */ internal fun String.checkPlaceholders( - supported: Set, + supported: Set, message: MessageType, file: File, option: String @@ -69,7 +69,7 @@ internal fun String.checkPlaceholders( * @param option The name of the option with which the message template was specified. */ internal fun String.checkPlaceholders( - supported: Set, + supported: Set, oneof: OneofGroup, file: File, option: String @@ -91,7 +91,7 @@ internal fun String.checkPlaceholders( * @param option The name of the option with which the message template was specified. */ public fun String.checkPlaceholders( - supported: Set, + supported: Set, field: Field, file: File, option: String @@ -108,7 +108,7 @@ public fun String.checkPlaceholders( * set of the [supported] placeholders, and reports a compilation error if so. */ private fun String.checkPlaceholders( - supported: Set, + supported: Set, declaration: String, span: Span, file: File, @@ -119,7 +119,7 @@ private fun String.checkPlaceholders( Compilation.check(missing.isEmpty(), file, span) { "The $declaration specifies an error message for the `($option)` option using unsupported" + " placeholders: `$missing`. Supported placeholders are the following:" + - " `${supported.map { it.value }}`." + " `${supported.map { it.name }}`." } } @@ -132,13 +132,12 @@ private fun String.checkPlaceholders( */ private fun missingPlaceholders( template: String, - placeholders: Set -): Set { + placeholders: Set +): Set { val requested = extractPlaceholders(template) - val provided = placeholders.map { it.value } - val missing = mutableSetOf() + val missing = mutableSetOf() for (placeholder in requested) { - if (!provided.contains(placeholder)) { + if (!placeholders.contains(placeholder)) { missing.add(placeholder) } } diff --git a/context/src/main/kotlin/io/spine/tools/validation/bound/MaxOption.kt b/context/src/main/kotlin/io/spine/tools/validation/bound/MaxOption.kt index b13829ea21..7360264422 100644 --- a/context/src/main/kotlin/io/spine/tools/validation/bound/MaxOption.kt +++ b/context/src/main/kotlin/io/spine/tools/validation/bound/MaxOption.kt @@ -48,12 +48,12 @@ import io.spine.tools.validation.checkPlaceholders import io.spine.tools.validation.defaultMessage import io.spine.tools.validation.option.MAX import io.spine.tools.validation.option.RANGE -import io.spine.validation.ErrorPlaceholder.FIELD_PATH -import io.spine.validation.ErrorPlaceholder.FIELD_TYPE -import io.spine.validation.ErrorPlaceholder.FIELD_VALUE -import io.spine.validation.ErrorPlaceholder.MAX_OPERATOR -import io.spine.validation.ErrorPlaceholder.MAX_VALUE -import io.spine.validation.ErrorPlaceholder.PARENT_TYPE +import io.spine.validation.StandardPlaceholder.FIELD_PATH +import io.spine.validation.StandardPlaceholder.FIELD_TYPE +import io.spine.validation.StandardPlaceholder.FIELD_VALUE +import io.spine.validation.StandardPlaceholder.MAX_OPERATOR +import io.spine.validation.StandardPlaceholder.MAX_VALUE +import io.spine.validation.StandardPlaceholder.PARENT_TYPE /** * A reaction to add a validation rule to a type whenever the `(max)` field option @@ -107,10 +107,10 @@ internal class MaxFieldView : View() { } private val SUPPORTED_PLACEHOLDERS = setOf( - FIELD_PATH, - FIELD_TYPE, - FIELD_VALUE, - MAX_OPERATOR, - MAX_VALUE, - PARENT_TYPE, + FIELD_PATH.value, + FIELD_TYPE.value, + FIELD_VALUE.value, + MAX_OPERATOR.value, + MAX_VALUE.value, + PARENT_TYPE.value, ) diff --git a/context/src/main/kotlin/io/spine/tools/validation/bound/MinOption.kt b/context/src/main/kotlin/io/spine/tools/validation/bound/MinOption.kt index 5cff14b387..2d1dc76939 100644 --- a/context/src/main/kotlin/io/spine/tools/validation/bound/MinOption.kt +++ b/context/src/main/kotlin/io/spine/tools/validation/bound/MinOption.kt @@ -48,12 +48,12 @@ import io.spine.tools.validation.checkPlaceholders import io.spine.tools.validation.defaultMessage import io.spine.tools.validation.option.MIN import io.spine.tools.validation.option.RANGE -import io.spine.validation.ErrorPlaceholder.FIELD_PATH -import io.spine.validation.ErrorPlaceholder.FIELD_TYPE -import io.spine.validation.ErrorPlaceholder.FIELD_VALUE -import io.spine.validation.ErrorPlaceholder.MIN_OPERATOR -import io.spine.validation.ErrorPlaceholder.MIN_VALUE -import io.spine.validation.ErrorPlaceholder.PARENT_TYPE +import io.spine.validation.StandardPlaceholder.FIELD_PATH +import io.spine.validation.StandardPlaceholder.FIELD_TYPE +import io.spine.validation.StandardPlaceholder.FIELD_VALUE +import io.spine.validation.StandardPlaceholder.MIN_OPERATOR +import io.spine.validation.StandardPlaceholder.MIN_VALUE +import io.spine.validation.StandardPlaceholder.PARENT_TYPE /** * A reaction to add a validation rule to a type whenever the `(min)` field option @@ -107,10 +107,10 @@ internal class MinFieldView : View() { } private val SUPPORTED_PLACEHOLDERS = setOf( - FIELD_PATH, - FIELD_TYPE, - FIELD_VALUE, - MIN_OPERATOR, - MIN_VALUE, - PARENT_TYPE, + FIELD_PATH.value, + FIELD_TYPE.value, + FIELD_VALUE.value, + MIN_OPERATOR.value, + MIN_VALUE.value, + PARENT_TYPE.value, ) diff --git a/context/src/main/kotlin/io/spine/tools/validation/bound/RangeOption.kt b/context/src/main/kotlin/io/spine/tools/validation/bound/RangeOption.kt index 82e777a408..c514bb2a61 100644 --- a/context/src/main/kotlin/io/spine/tools/validation/bound/RangeOption.kt +++ b/context/src/main/kotlin/io/spine/tools/validation/bound/RangeOption.kt @@ -51,11 +51,11 @@ import io.spine.tools.validation.bound.event.rangeFieldDiscovered import io.spine.tools.validation.checkPlaceholders import io.spine.tools.validation.defaultMessage import io.spine.tools.validation.option.RANGE -import io.spine.validation.ErrorPlaceholder.FIELD_PATH -import io.spine.validation.ErrorPlaceholder.FIELD_TYPE -import io.spine.validation.ErrorPlaceholder.FIELD_VALUE -import io.spine.validation.ErrorPlaceholder.PARENT_TYPE -import io.spine.validation.ErrorPlaceholder.RANGE_VALUE +import io.spine.validation.StandardPlaceholder.FIELD_PATH +import io.spine.validation.StandardPlaceholder.FIELD_TYPE +import io.spine.validation.StandardPlaceholder.FIELD_VALUE +import io.spine.validation.StandardPlaceholder.PARENT_TYPE +import io.spine.validation.StandardPlaceholder.RANGE_VALUE /** * Controls whether a field should be validated with the `(range)` option. @@ -226,9 +226,9 @@ private fun RangeOptionMetadata.checkRelation(lower: KNumericBound, upper: KNume private val DELIMITER = Regex("""(?<=[\p{Alnum}_])\s?\.\.\s?(?=[\p{Alnum}-+_])""") private val SUPPORTED_PLACEHOLDERS = setOf( - FIELD_PATH, - FIELD_TYPE, - FIELD_VALUE, - PARENT_TYPE, - RANGE_VALUE, + FIELD_PATH.value, + FIELD_TYPE.value, + FIELD_VALUE.value, + PARENT_TYPE.value, + RANGE_VALUE.value, ) diff --git a/context/src/main/kotlin/io/spine/tools/validation/option/ChoiceOption.kt b/context/src/main/kotlin/io/spine/tools/validation/option/ChoiceOption.kt index e07f4d3aca..a9d9241e32 100644 --- a/context/src/main/kotlin/io/spine/tools/validation/option/ChoiceOption.kt +++ b/context/src/main/kotlin/io/spine/tools/validation/option/ChoiceOption.kt @@ -49,8 +49,8 @@ import io.spine.tools.validation.checkPlaceholders import io.spine.tools.validation.defaultMessage import io.spine.tools.validation.event.ChoiceOneofDiscovered import io.spine.tools.validation.event.choiceOneofDiscovered -import io.spine.validation.ErrorPlaceholder.GROUP_PATH -import io.spine.validation.ErrorPlaceholder.PARENT_TYPE +import io.spine.validation.StandardPlaceholder.GROUP_PATH +import io.spine.validation.StandardPlaceholder.PARENT_TYPE /** * Controls whether a `oneof` group should be validated with the `(choice)` option. @@ -128,6 +128,6 @@ internal class ChoiceGroupView : View ```kotlin -val validationVersion by extra("2.0.0-SNAPSHOT.421") +val validationVersion by extra("2.0.0-SNAPSHOT.430") ``` The root build script applies this file under `allprojects { … }` and assigns diff --git a/docs/content/docs/validation/developer/runtime-library.md b/docs/content/docs/validation/developer/runtime-library.md index b3a19e088b..bd5fff7c54 100644 --- a/docs/content/docs/validation/developer/runtime-library.md +++ b/docs/content/docs/validation/developer/runtime-library.md @@ -27,7 +27,7 @@ Five groups of types live in the runtime library: | Violation Protobuf | `ValidationError`, `ConstraintViolation`, `TemplateString` | The structured shape of a violation report. | | Exception | `ValidationException` | Thrown by `Builder.build()` when validation fails. | | Markers | `@Validated`, `@NonValidated` | Documentary annotations placed on `build()` and `buildPartial()` return types; not retained at runtime. | -| Validator extension | `MessageValidator`, `ValidatorRegistry`, `DetectedViolation`, `ErrorPlaceholder` | Runtime SPI for attaching custom checks to a message type, including third-party messages. | +| Validator extension | `MessageValidator`, `ValidatorRegistry`, `DetectedViolation`, `Placeholder` | Runtime SPI for attaching custom checks to a message type, including third-party messages. | Two utility entry points round the surface out: the static method `Validate.check(message)` and the Kotlin extensions `M.checkValid()` and `M.copy { … }` in @@ -189,7 +189,7 @@ every problem in one pass. generator emits and every reader resolves. Substitution happens via `TemplateString.format()` (in Kotlin, [`TemplateStringExts.kt`][template-string-exts]) or the static `TemplateStrings.format(...)` (in Java). The placeholder names the runtime -itself fills in are enumerated by [`ErrorPlaceholder`][error-placeholder] +itself fills in are enumerated by [`StandardPlaceholder`][standard-placeholder] — `field.path`, `field.value`, `field.type`, `message.type`, `parent.type`, plus option-specific entries such as `regex.pattern` and `range.value`. @@ -385,5 +385,5 @@ in `:context` and `:java`: anything that *can* be decided at build time *should* [exception-factory]: https://github.com/SpineEventEngine/validation/blob/master/jvm-runtime/src/main/java/io/spine/validation/ExceptionFactory.java [message-extensions]: https://github.com/SpineEventEngine/validation/blob/master/jvm-runtime/src/main/kotlin/io/spine/validation/MessageExtensions.kt [template-string-exts]: https://github.com/SpineEventEngine/validation/blob/master/jvm-runtime/src/main/kotlin/io/spine/validation/TemplateStringExts.kt -[error-placeholder]: https://github.com/SpineEventEngine/validation/blob/master/jvm-runtime/src/main/kotlin/io/spine/validation/ErrorPlaceholder.kt +[standard-placeholder]: https://github.com/SpineEventEngine/validation/blob/master/jvm-runtime/src/main/kotlin/io/spine/validation/StandardPlaceholder.kt [timestamp-validator]: https://github.com/SpineEventEngine/validation/blob/master/jvm-runtime/src/main/kotlin/io/spine/validation/TimestampValidator.kt diff --git a/docs/content/docs/validation/developer/validation-model.md b/docs/content/docs/validation/developer/validation-model.md index cd4418c41b..52ad8052de 100644 --- a/docs/content/docs/validation/developer/validation-model.md +++ b/docs/content/docs/validation/developer/validation-model.md @@ -298,13 +298,13 @@ not free-form. Each option declares the placeholders it supports, and the reacti validates the template before the event is emitted: ```kotlin private fun String.checkPlaceholders( - supported: Set, + supported: Set, declaration: String, span: Span, file: File, @@ -315,7 +315,7 @@ private fun String.checkPlaceholders( Compilation.check(missing.isEmpty(), file, span) { "The $declaration specifies an error message for the `($option)` option using unsupported" + " placeholders: `$missing`. Supported placeholders are the following:" + - " `${supported.map { it.value }}`." + " `${supported.map { it.name }}`." } } ``` @@ -323,7 +323,7 @@ private fun String.checkPlaceholders( Catching unknown placeholders here, in the model, is what allows the renderer to assume that every placeholder it sees in the projection state has a known meaning. The full list of placeholders for generated validation code is enumerated in -[`ErrorPlaceholder.kt`][error-placeholder]. At runtime, `TemplateString` carries +[`StandardPlaceholder.kt`][standard-placeholder]. At runtime, `TemplateString` carries placeholder keys as strings; the runtime library does not keep a second placeholder enum. When no custom message is provided, the reaction falls back to the option's @@ -378,6 +378,6 @@ consumer-facing version of the same SPI is covered by [option-name]: https://github.com/SpineEventEngine/validation/blob/master/context/src/main/kotlin/io/spine/tools/validation/OptionName.kt [option-names]: https://github.com/SpineEventEngine/validation/blob/master/context/src/main/kotlin/io/spine/tools/validation/option/OptionNames.kt [bound-pkg]: https://github.com/SpineEventEngine/validation/tree/master/context/src/main/kotlin/io/spine/tools/validation/bound -[error-placeholder]: https://github.com/SpineEventEngine/validation/blob/master/jvm-runtime/src/main/kotlin/io/spine/validation/ErrorPlaceholder.kt +[standard-placeholder]: https://github.com/SpineEventEngine/validation/blob/master/jvm-runtime/src/main/kotlin/io/spine/validation/StandardPlaceholder.kt [default-message]: https://github.com/SpineEventEngine/validation/blob/master/context/src/main/kotlin/io/spine/tools/validation/DefaultErrorMessage.kt [validation-option-spi]: https://github.com/SpineEventEngine/validation/blob/master/java/src/main/kotlin/io/spine/tools/validation/java/ValidationOption.kt diff --git a/docs/content/docs/validation/user/01-getting-started/adding-to-build.md b/docs/content/docs/validation/user/01-getting-started/adding-to-build.md index ab88f3805d..74b137cacb 100644 --- a/docs/content/docs/validation/user/01-getting-started/adding-to-build.md +++ b/docs/content/docs/validation/user/01-getting-started/adding-to-build.md @@ -90,7 +90,7 @@ Add the Validation plugin to the build. ```kotlin plugins { module - id("io.spine.validation") version "2.0.0-SNAPSHOT.421" + id("io.spine.validation") version "2.0.0-SNAPSHOT.430" } ``` diff --git a/docs/dependencies/dependencies.md b/docs/dependencies/dependencies.md index 1e01107cbe..8ef411d895 100644 --- a/docs/dependencies/dependencies.md +++ b/docs/dependencies/dependencies.md @@ -1,6 +1,6 @@ -# Dependencies of `io.spine.tools:validation-context:2.0.0-SNAPSHOT.421` +# Dependencies of `io.spine.tools:validation-context:2.0.0-SNAPSHOT.430` ## Runtime 1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.20.0. @@ -1090,14 +1090,14 @@ The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu May 14 20:38:23 WEST 2026** using +This report was generated on **Sat May 16 17:35:16 WEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.tools:validation-context-tests:2.0.0-SNAPSHOT.421` +# Dependencies of `io.spine.tools:validation-context-tests:2.0.0-SNAPSHOT.430` ## Runtime 1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.20.0. @@ -1791,28 +1791,28 @@ This report was generated on **Thu May 14 20:38:23 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu May 14 20:38:22 WEST 2026** using +This report was generated on **Sat May 16 17:35:16 WEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.tools:validation-docs:2.0.0-SNAPSHOT.420` +# Dependencies of `io.spine.tools:validation-docs:2.0.0-SNAPSHOT.430` ## Runtime ## Compile, tests, and tooling The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed May 13 20:09:04 WEST 2026** using +This report was generated on **Sat May 16 15:49:45 WEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.tools:validation-gradle-plugin:2.0.0-SNAPSHOT.421` +# Dependencies of `io.spine.tools:validation-gradle-plugin:2.0.0-SNAPSHOT.430` ## Runtime 1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.20.0. @@ -2864,14 +2864,14 @@ This report was generated on **Wed May 13 20:09:04 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu May 14 20:38:23 WEST 2026** using +This report was generated on **Sat May 16 17:35:16 WEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.tools:validation-java:2.0.0-SNAPSHOT.421` +# Dependencies of `io.spine.tools:validation-java:2.0.0-SNAPSHOT.430` ## Runtime 1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.20.0. @@ -3961,14 +3961,14 @@ This report was generated on **Thu May 14 20:38:23 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu May 14 20:38:23 WEST 2026** using +This report was generated on **Sat May 16 17:35:16 WEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.tools:validation-java-bundle:2.0.0-SNAPSHOT.421` +# Dependencies of `io.spine.tools:validation-java-bundle:2.0.0-SNAPSHOT.430` ## Runtime 1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 13.0. @@ -4015,14 +4015,14 @@ This report was generated on **Thu May 14 20:38:23 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu May 14 20:38:19 WEST 2026** using +This report was generated on **Sat May 16 17:35:15 WEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine:spine-validation-jvm-runtime:2.0.0-SNAPSHOT.421` +# Dependencies of `io.spine:spine-validation-jvm-runtime:2.0.0-SNAPSHOT.430` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -4822,14 +4822,14 @@ This report was generated on **Thu May 14 20:38:19 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu May 14 20:38:23 WEST 2026** using +This report was generated on **Sat May 16 17:35:16 WEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.tools:validation-consumer:2.0.0-SNAPSHOT.421` +# Dependencies of `io.spine.tools:validation-consumer:2.0.0-SNAPSHOT.430` ## Runtime 1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.20.0. @@ -5511,14 +5511,14 @@ This report was generated on **Thu May 14 20:38:23 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu May 14 20:38:22 WEST 2026** using +This report was generated on **Sat May 16 17:35:16 WEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.tools:validation-consumer-dependency:2.0.0-SNAPSHOT.421` +# Dependencies of `io.spine.tools:validation-consumer-dependency:2.0.0-SNAPSHOT.430` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -5976,14 +5976,14 @@ This report was generated on **Thu May 14 20:38:22 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu May 14 20:38:22 WEST 2026** using +This report was generated on **Sat May 16 17:35:16 WEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.tools:validation-extensions:2.0.0-SNAPSHOT.421` +# Dependencies of `io.spine.tools:validation-extensions:2.0.0-SNAPSHOT.430` ## Runtime 1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.20.0. @@ -6602,14 +6602,14 @@ This report was generated on **Thu May 14 20:38:22 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu May 14 20:38:21 WEST 2026** using +This report was generated on **Sat May 16 17:35:16 WEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.tools:validation-runtime:2.0.0-SNAPSHOT.421` +# Dependencies of `io.spine.tools:validation-runtime:2.0.0-SNAPSHOT.430` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -7170,14 +7170,443 @@ This report was generated on **Thu May 14 20:38:21 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu May 14 20:38:22 WEST 2026** using +This report was generated on **Sat May 16 17:35:16 WEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.tools:validation-validating:2.0.0-SNAPSHOT.421` +# Dependencies of `io.spine.tools:validation-time:2.0.0-SNAPSHOT.430` + +## Runtime +1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. + * **Project URL:** [http://findbugs.sourceforge.net/](http://findbugs.sourceforge.net/) + * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.google.code.gson. **Name** : gson. **Version** : 2.8.9. + * **Project URL:** [https://github.com/google/gson/gson](https://github.com/google/gson/gson) + * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.google.errorprone. **Name** : error_prone_annotations. **Version** : 2.41.0. + * **Project URL:** [https://errorprone.info/error_prone_annotations](https://errorprone.info/error_prone_annotations) + * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.google.guava. **Name** : failureaccess. **Version** : 1.0.3. + * **Project URL:** [https://github.com/google/guava/](https://github.com/google/guava/) + * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.google.guava. **Name** : guava. **Version** : 33.5.0-jre. + * **Project URL:** [https://github.com/google/guava](https://github.com/google/guava) + * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.google.guava. **Name** : listenablefuture. **Version** : 9999.0-empty-to-avoid-conflict-with-guava. + * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.google.j2objc. **Name** : j2objc-annotations. **Version** : 3.1. + * **Project URL:** [https://github.com/google/j2objc/](https://github.com/google/j2objc/) + * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.google.protobuf. **Name** : protobuf-java. **Version** : 4.34.1. + * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) + * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) + +1. **Group** : com.google.protobuf. **Name** : protobuf-java-util. **Version** : 4.34.1. + * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) + * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) + +1. **Group** : com.google.protobuf. **Name** : protobuf-kotlin. **Version** : 4.34.1. + * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) + * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) + +1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 13.0. + * **Project URL:** [http://www.jetbrains.org](http://www.jetbrains.org) + * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-bom. **Version** : 2.3.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-reflect. **Version** : 2.3.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib. **Version** : 2.3.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-coroutines-bom. **Version** : 1.10.2. + * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) + * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jspecify. **Name** : jspecify. **Version** : 1.0.0. + * **Project URL:** [http://jspecify.org/](http://jspecify.org/) + * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +## Compile, tests, and tooling +1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.20.0. + * **Project URL:** [https://github.com/FasterXML/jackson-bom](https://github.com/FasterXML/jackson-bom) + * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-annotations. **Version** : 2.20. + * **Project URL:** [https://github.com/FasterXML/jackson](https://github.com/FasterXML/jackson) + * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-core. **Version** : 2.20.0. + * **Project URL:** [https://github.com/FasterXML/jackson-core](https://github.com/FasterXML/jackson-core) + * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-databind. **Version** : 2.20.0. + * **Project URL:** [https://github.com/FasterXML/jackson](https://github.com/FasterXML/jackson) + * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-guava. **Version** : 2.20.0. + * **Project URL:** [https://github.com/FasterXML/jackson-datatypes-collections](https://github.com/FasterXML/jackson-datatypes-collections) + * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-jdk8. **Version** : 2.20.0. + * **Project URL:** [https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8](https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8) + * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.fasterxml.jackson.module. **Name** : jackson-module-parameter-names. **Version** : 2.20.0. + * **Project URL:** [https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names](https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names) + * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.google.auto.value. **Name** : auto-value-annotations. **Version** : 1.11.0. + * **Project URL:** [https://github.com/google/auto/tree/main/value](https://github.com/google/auto/tree/main/value) + * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. + * **Project URL:** [http://findbugs.sourceforge.net/](http://findbugs.sourceforge.net/) + * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.google.code.gson. **Name** : gson. **Version** : 2.8.9. + * **Project URL:** [https://github.com/google/gson/gson](https://github.com/google/gson/gson) + * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.google.errorprone. **Name** : error_prone_annotations. **Version** : 2.41.0. + * **Project URL:** [https://errorprone.info/error_prone_annotations](https://errorprone.info/error_prone_annotations) + * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.google.errorprone. **Name** : error_prone_type_annotations. **Version** : 2.36.0. + * **Project URL:** [https://errorprone.info/error_prone_type_annotations](https://errorprone.info/error_prone_type_annotations) + * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.google.flogger. **Name** : flogger. **Version** : 0.7.4. + * **Project URL:** [https://github.com/google/flogger](https://github.com/google/flogger) + * **License:** [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.google.flogger. **Name** : flogger-system-backend. **Version** : 0.7.4. + * **Project URL:** [https://github.com/google/flogger](https://github.com/google/flogger) + * **License:** [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.google.guava. **Name** : failureaccess. **Version** : 1.0.3. + * **Project URL:** [https://github.com/google/guava/](https://github.com/google/guava/) + * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.google.guava. **Name** : guava. **Version** : 33.5.0-jre. + * **Project URL:** [https://github.com/google/guava](https://github.com/google/guava) + * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.google.guava. **Name** : guava-testlib. **Version** : 33.5.0-jre. + * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.google.guava. **Name** : listenablefuture. **Version** : 9999.0-empty-to-avoid-conflict-with-guava. + * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.google.j2objc. **Name** : j2objc-annotations. **Version** : 3.1. + * **Project URL:** [https://github.com/google/j2objc/](https://github.com/google/j2objc/) + * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.google.protobuf. **Name** : protobuf-java. **Version** : 4.34.1. + * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) + * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) + +1. **Group** : com.google.protobuf. **Name** : protobuf-java-util. **Version** : 4.34.1. + * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) + * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) + +1. **Group** : com.google.protobuf. **Name** : protobuf-kotlin. **Version** : 4.34.1. + * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) + * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) + +1. **Group** : com.google.protobuf. **Name** : protoc. **Version** : 4.34.1. + * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) + * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) + * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.google.truth. **Name** : truth. **Version** : 1.4.4. + * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.google.truth.extensions. **Name** : truth-java8-extension. **Version** : 1.4.4. + * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.google.truth.extensions. **Name** : truth-liteproto-extension. **Version** : 1.4.4. + * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.google.truth.extensions. **Name** : truth-proto-extension. **Version** : 1.4.4. + * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format. **Version** : 2.75.0. + * **Project URL:** [https://github.com/palantir/palantir-java-format](https://github.com/palantir/palantir-java-format) + * **License:** [The Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) + +1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format-spi. **Version** : 2.75.0. + * **Project URL:** [https://github.com/palantir/palantir-java-format](https://github.com/palantir/palantir-java-format) + * **License:** [The Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) + +1. **Group** : io.github.java-diff-utils. **Name** : java-diff-utils. **Version** : 4.12. + * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : io.github.java-diff-utils. **Name** : java-diff-utils. **Version** : 4.16. + * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : io.kotest. **Name** : kotest-assertions-core. **Version** : 6.1.11. + * **Project URL:** [https://github.com/kotest/kotest](https://github.com/kotest/kotest) + * **License:** [Apache-2.0](https://opensource.org/licenses/Apache-2.0) + +1. **Group** : io.kotest. **Name** : kotest-assertions-core-jvm. **Version** : 6.1.11. + * **Project URL:** [https://github.com/kotest/kotest](https://github.com/kotest/kotest) + * **License:** [Apache-2.0](https://opensource.org/licenses/Apache-2.0) + +1. **Group** : io.kotest. **Name** : kotest-assertions-shared. **Version** : 6.1.11. + * **Project URL:** [https://github.com/kotest/kotest](https://github.com/kotest/kotest) + * **License:** [Apache-2.0](https://opensource.org/licenses/Apache-2.0) + +1. **Group** : io.kotest. **Name** : kotest-assertions-shared-jvm. **Version** : 6.1.11. + * **Project URL:** [https://github.com/kotest/kotest](https://github.com/kotest/kotest) + * **License:** [Apache-2.0](https://opensource.org/licenses/Apache-2.0) + +1. **Group** : io.kotest. **Name** : kotest-common. **Version** : 6.1.11. + * **Project URL:** [https://github.com/kotest/kotest](https://github.com/kotest/kotest) + * **License:** [Apache-2.0](https://opensource.org/licenses/Apache-2.0) + +1. **Group** : io.kotest. **Name** : kotest-common-jvm. **Version** : 6.1.11. + * **Project URL:** [https://github.com/kotest/kotest](https://github.com/kotest/kotest) + * **License:** [Apache-2.0](https://opensource.org/licenses/Apache-2.0) + +1. **Group** : junit. **Name** : junit. **Version** : 4.13.2. + * **Project URL:** [http://junit.org](http://junit.org) + * **License:** [Eclipse Public License 1.0](http://www.eclipse.org/legal/epl-v10.html) + +1. **Group** : org.apiguardian. **Name** : apiguardian-api. **Version** : 1.1.2. + * **Project URL:** [https://github.com/apiguardian-team/apiguardian](https://github.com/apiguardian-team/apiguardian) + * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.checkerframework. **Name** : checker-compat-qual. **Version** : 2.5.3. + * **Project URL:** [https://checkerframework.org](https://checkerframework.org) + * **License:** [GNU General Public License, version 2 (GPL2), with the classpath exception](http://www.gnu.org/software/classpath/license.html) + * **License:** [The MIT License](http://opensource.org/licenses/MIT) + +1. **Group** : org.checkerframework. **Name** : checker-qual. **Version** : 3.40.0. + * **Project URL:** [https://checkerframework.org/](https://checkerframework.org/) + * **License:** [The MIT License](http://opensource.org/licenses/MIT) + +1. **Group** : org.functionaljava. **Name** : functionaljava. **Version** : 4.8. + * **Project URL:** [http://functionaljava.org/](http://functionaljava.org/) + * **License:** [The BSD3 License](https://github.com/functionaljava/functionaljava/blob/master/etc/LICENCE) + +1. **Group** : org.hamcrest. **Name** : hamcrest-core. **Version** : 1.3. + * **License:** [New BSD License](http://www.opensource.org/licenses/bsd-license.php) + +1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 13.0. + * **Project URL:** [http://www.jetbrains.org](http://www.jetbrains.org) + * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 23.0.0. + * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) + * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlin. **Name** : abi-tools. **Version** : 2.3.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlin. **Name** : abi-tools-api. **Version** : 2.3.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-bom. **Version** : 2.3.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-api. **Version** : 2.3.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-compat. **Version** : 2.3.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-cri-impl. **Version** : 2.3.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-impl. **Version** : 2.3.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-compiler-embeddable. **Version** : 2.3.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-compiler-runner. **Version** : 2.3.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-daemon-client. **Version** : 2.3.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-daemon-embeddable. **Version** : 2.3.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-klib-abi-reader. **Version** : 2.3.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-klib-commonizer-embeddable. **Version** : 2.3.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-metadata-jvm. **Version** : 2.3.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-reflect. **Version** : 2.3.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-script-runtime. **Version** : 2.3.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-scripting-common. **Version** : 2.3.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-scripting-compiler-embeddable. **Version** : 2.3.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-scripting-compiler-impl-embeddable. **Version** : 2.3.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-scripting-jvm. **Version** : 2.3.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib. **Version** : 2.3.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-tooling-core. **Version** : 2.3.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlinx. **Name** : atomicfu. **Version** : 0.29.0. + * **Project URL:** [https://github.com/Kotlin/kotlinx.atomicfu](https://github.com/Kotlin/kotlinx.atomicfu) + * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlinx. **Name** : atomicfu-jvm. **Version** : 0.29.0. + * **Project URL:** [https://github.com/Kotlin/kotlinx.atomicfu](https://github.com/Kotlin/kotlinx.atomicfu) + * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-coroutines-bom. **Version** : 1.10.2. + * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) + * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-coroutines-core. **Version** : 1.10.2. + * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) + * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-coroutines-core-jvm. **Version** : 1.10.2. + * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) + * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-coroutines-jdk8. **Version** : 1.10.2. + * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) + * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-coroutines-test. **Version** : 1.10.2. + * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) + * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-coroutines-test-jvm. **Version** : 1.10.2. + * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) + * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.7.1. + * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) + * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.7.1. + * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) + * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.jspecify. **Name** : jspecify. **Version** : 1.0.0. + * **Project URL:** [http://jspecify.org/](http://jspecify.org/) + * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.junit. **Name** : junit-bom. **Version** : 6.0.3. + * **Project URL:** [https://junit.org/](https://junit.org/) + * **License:** [Eclipse Public License v2.0](https://www.eclipse.org/legal/epl-v20.html) + +1. **Group** : org.junit-pioneer. **Name** : junit-pioneer. **Version** : 2.3.0. + * **Project URL:** [https://junit-pioneer.org/](https://junit-pioneer.org/) + * **License:** [Eclipse Public License v2.0](https://www.eclipse.org/legal/epl-v20.html) + +1. **Group** : org.junit.jupiter. **Name** : junit-jupiter-api. **Version** : 6.0.3. + * **Project URL:** [https://junit.org/](https://junit.org/) + * **License:** [Eclipse Public License v2.0](https://www.eclipse.org/legal/epl-v20.html) + +1. **Group** : org.junit.jupiter. **Name** : junit-jupiter-engine. **Version** : 6.0.3. + * **Project URL:** [https://junit.org/](https://junit.org/) + * **License:** [Eclipse Public License v2.0](https://www.eclipse.org/legal/epl-v20.html) + +1. **Group** : org.junit.jupiter. **Name** : junit-jupiter-params. **Version** : 6.0.3. + * **Project URL:** [https://junit.org/](https://junit.org/) + * **License:** [Eclipse Public License v2.0](https://www.eclipse.org/legal/epl-v20.html) + +1. **Group** : org.junit.platform. **Name** : junit-platform-commons. **Version** : 6.0.3. + * **Project URL:** [https://junit.org/](https://junit.org/) + * **License:** [Eclipse Public License v2.0](https://www.eclipse.org/legal/epl-v20.html) + +1. **Group** : org.junit.platform. **Name** : junit-platform-engine. **Version** : 6.0.3. + * **Project URL:** [https://junit.org/](https://junit.org/) + * **License:** [Eclipse Public License v2.0](https://www.eclipse.org/legal/epl-v20.html) + +1. **Group** : org.junit.platform. **Name** : junit-platform-launcher. **Version** : 6.0.3. + * **Project URL:** [https://junit.org/](https://junit.org/) + * **License:** [Eclipse Public License v2.0](https://www.eclipse.org/legal/epl-v20.html) + +1. **Group** : org.opentest4j. **Name** : opentest4j. **Version** : 1.3.0. + * **Project URL:** [https://github.com/ota4j-team/opentest4j](https://github.com/ota4j-team/opentest4j) + * **License:** [The Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + +1. **Group** : org.ow2.asm. **Name** : asm. **Version** : 9.7. + * **Project URL:** [http://asm.ow2.io/](http://asm.ow2.io/) + * **License:** [BSD-3-Clause](https://asm.ow2.io/license.html) + * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + + +The dependencies distributed under several licenses, are used according their commercial-use-friendly license. + +This report was generated on **Sat May 16 17:35:16 WEST 2026** using +[Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under +[Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). + + + + +# Dependencies of `io.spine.tools:validation-validating:2.0.0-SNAPSHOT.430` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -7781,14 +8210,14 @@ This report was generated on **Thu May 14 20:38:22 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu May 14 20:38:22 WEST 2026** using +This report was generated on **Sat May 16 17:35:16 WEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.tools:validation-validator:2.0.0-SNAPSHOT.421` +# Dependencies of `io.spine.tools:validation-validator:2.0.0-SNAPSHOT.430` ## Runtime 1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.20.0. @@ -8526,14 +8955,14 @@ This report was generated on **Thu May 14 20:38:22 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu May 14 20:38:22 WEST 2026** using +This report was generated on **Sat May 16 17:35:16 WEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.tools:validation-validator-dependency:2.0.0-SNAPSHOT.421` +# Dependencies of `io.spine.tools:validation-validator-dependency:2.0.0-SNAPSHOT.430` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -8766,14 +9195,14 @@ This report was generated on **Thu May 14 20:38:22 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu May 14 20:38:21 WEST 2026** using +This report was generated on **Sat May 16 17:35:16 WEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.tools:validation-vanilla:2.0.0-SNAPSHOT.421` +# Dependencies of `io.spine.tools:validation-vanilla:2.0.0-SNAPSHOT.430` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -9116,6 +9545,6 @@ This report was generated on **Thu May 14 20:38:21 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu May 14 20:38:21 WEST 2026** using +This report was generated on **Sat May 16 17:35:16 WEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file diff --git a/docs/dependencies/pom.xml b/docs/dependencies/pom.xml index 133b9969ac..8ef187585d 100644 --- a/docs/dependencies/pom.xml +++ b/docs/dependencies/pom.xml @@ -10,7 +10,7 @@ all modules and does not describe the project structure per-subproject. --> io.spine.tools validation -2.0.0-SNAPSHOT.421 +2.0.0-SNAPSHOT.430 2015 @@ -50,19 +50,25 @@ all modules and does not describe the project structure per-subproject. io.spine spine-base - 2.0.0-SNAPSHOT.387 + 2.0.0-SNAPSHOT.389 compile io.spine spine-time - 2.0.0-SNAPSHOT.238 + 2.0.0-SNAPSHOT.240 + compile + + + io.spine + spine-time-java + 2.0.0-SNAPSHOT.240 compile io.spine spine-validation-jvm-runtime - 2.0.0-SNAPSHOT.415 + 2.0.0-SNAPSHOT.419 compile @@ -269,7 +275,7 @@ all modules and does not describe the project structure per-subproject. io.spine.tools core-jvm-plugins - 2.0.0-SNAPSHOT.063 + 2.0.0-SNAPSHOT.064 io.spine.tools @@ -284,12 +290,12 @@ all modules and does not describe the project structure per-subproject. io.spine.tools time-validation - 2.0.0-SNAPSHOT.236 + 2.0.0-SNAPSHOT.240 io.spine.tools validation-java-bundle - 2.0.0-SNAPSHOT.415 + 2.0.0-SNAPSHOT.419 net.sourceforge.pmd diff --git a/java/src/main/kotlin/io/spine/tools/validation/java/expression/ClassNames.kt b/java/src/main/kotlin/io/spine/tools/validation/java/expression/ClassNames.kt index 895c86bedb..19da1c4b4c 100644 --- a/java/src/main/kotlin/io/spine/tools/validation/java/expression/ClassNames.kt +++ b/java/src/main/kotlin/io/spine/tools/validation/java/expression/ClassNames.kt @@ -43,7 +43,7 @@ import io.spine.type.KnownTypes import io.spine.type.TypeName import io.spine.type.TypeUrl import io.spine.validation.ConstraintViolation -import io.spine.validation.TemplateString +import io.spine.string.TemplateString import io.spine.validation.ValidatableMessage import io.spine.validation.ValidationError import java.util.* diff --git a/java/src/main/kotlin/io/spine/tools/validation/java/expression/ConstraintViolations.kt b/java/src/main/kotlin/io/spine/tools/validation/java/expression/ConstraintViolations.kt index 223f4031e0..71613781fe 100644 --- a/java/src/main/kotlin/io/spine/tools/validation/java/expression/ConstraintViolations.kt +++ b/java/src/main/kotlin/io/spine/tools/validation/java/expression/ConstraintViolations.kt @@ -34,7 +34,7 @@ import io.spine.tools.compiler.jvm.Expression import io.spine.tools.compiler.jvm.newBuilder import io.spine.tools.compiler.jvm.packToAny import io.spine.validation.ConstraintViolation -import io.spine.validation.TemplateString +import io.spine.string.TemplateString /** * Yields an expression that creates a new instance of [ConstraintViolation] diff --git a/java/src/main/kotlin/io/spine/tools/validation/java/expression/TemplateStrings.kt b/java/src/main/kotlin/io/spine/tools/validation/java/expression/TemplateStrings.kt index 3314aa9de0..56156c88e5 100644 --- a/java/src/main/kotlin/io/spine/tools/validation/java/expression/TemplateStrings.kt +++ b/java/src/main/kotlin/io/spine/tools/validation/java/expression/TemplateStrings.kt @@ -33,74 +33,35 @@ import io.spine.tools.compiler.jvm.Expression import io.spine.tools.compiler.jvm.StringLiteral import io.spine.tools.compiler.jvm.mapExpression import io.spine.tools.compiler.jvm.newBuilder -import io.spine.validation.ErrorPlaceholder -import io.spine.validation.TemplateString -import io.spine.validation.checkPlaceholdersHasValue +import io.spine.string.Placeholder +import io.spine.string.TemplateString +import io.spine.string.joinQuoted /** * Yields an expression that creates a new instance of [TemplateString]. * * Note that this method differs from the one provided by the API module - * in that it accepts placeholder keys as [ErrorPlaceholder]. This enum - * contains placeholder keys for built-in options. + * in that it accepts placeholder keys as [Placeholder]. The standard + * placeholder keys for built-in options are provided by [io.spine.validation.StandardPlaceholder]. * * @param placeholders The supported placeholders and their values. * @param optionName The name of the option, which declared the provided [placeholders]. */ -@JvmName("templateStringExp") public fun templateString( template: String, - placeholders: Map>, - optionName: String -): Expression = - withStringPlaceholders(template, placeholders.mapKeys { it.key.value }, optionName) - -/** - * Yields an expression that creates a new instance of [TemplateString]. - * - * This overload accepts the deprecated placeholders from the former - * `io.spine.tools.validation` package. - * - * @param placeholders The supported placeholders and their values. - * @param optionName The name of the option, which declared the provided [placeholders]. - */ -@Suppress("DEPRECATION") -@Deprecated( - message = "Please use the overload accepting `io.spine.validation.ErrorPlaceholder`." -) -public fun templateString( - template: String, - placeholders: Map>, - optionName: String -): Expression { - val runtimePlaceholders = placeholders.mapKeys { it.key.toRuntime() } - return withStringPlaceholders( - template, - runtimePlaceholders.mapKeys { it.key.value }, - optionName - ) -} - -/** - * Yields an expression that creates a new instance of [TemplateString]. - * - * @param placeholders The supported placeholders and their values. - * @param optionName The name of the option, which declared the provided [placeholders]. - */ -public fun withStringPlaceholders( - template: String, - placeholders: Map>, + placeholders: Map>, optionName: String ): Expression { - checkPlaceholdersHasValue(template, placeholders) { missingKeys -> - "Unexpected error message placeholders `$missingKeys` specified for the `($optionName)`" + - " option. The available placeholders: `${placeholders.keys}`. Please make sure" + - " that the code that verifies the message placeholders and its code generator" + - " operate with the same set of placeholders." + checkPlaceholdersHasValue(template, placeholders.keys) { missing -> + "Unexpected error message placeholders ${missing.joinQuoted()} specified for" + + " the `($optionName)` option." + + " The available placeholders: ${placeholders.keys.joinQuoted()}." + + " Please make sure that the code that verifies the message placeholders and" + + " its code generator operate with the same set of placeholders." } val placeholderEntries = mapExpression( StringClass, StringClass, - placeholders.mapKeys { StringLiteral(it.key) } + placeholders.mapKeys { StringLiteral(it.key.name) } ) val escapedTemplate = restoreProtobufEscapes(template) return TemplateStringClass.newBuilder() @@ -108,3 +69,22 @@ public fun withStringPlaceholders( .chainPutAll("placeholderValue", placeholderEntries) .chainBuild() } + +/** + * Makes sure that each placeholder within the [template] string is present + * in the [placeholders] set. + * + * @param template The template with placeholders like `${something}`. + * @param placeholders The set of available placeholders. + */ +private fun checkPlaceholdersHasValue( + template: String, + placeholders: Set, + lazyMessage: (List) -> String +) { + val needed = Placeholder.extractPlaceholders(template) + val missing = needed.filter { it !in placeholders } + if (missing.isNotEmpty()) { + throw IllegalArgumentException(lazyMessage(missing)) + } +} diff --git a/java/src/main/kotlin/io/spine/tools/validation/java/generate/ValidatorGenerator.kt b/java/src/main/kotlin/io/spine/tools/validation/java/generate/ValidatorGenerator.kt index a612304fc6..49fe678efe 100644 --- a/java/src/main/kotlin/io/spine/tools/validation/java/generate/ValidatorGenerator.kt +++ b/java/src/main/kotlin/io/spine/tools/validation/java/generate/ValidatorGenerator.kt @@ -57,7 +57,7 @@ import io.spine.tools.validation.java.generate.ValidateScope.parentPath import io.spine.tools.validation.java.generate.ValidateScope.violations import io.spine.validation.ConstraintViolation import io.spine.validation.DetectedViolation -import io.spine.validation.TemplateString +import io.spine.string.TemplateString /** * A fully qualified Java class name of a validator class. diff --git a/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/ChoiceGenerator.kt b/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/ChoiceGenerator.kt index d25faf42b8..1e0caaa859 100644 --- a/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/ChoiceGenerator.kt +++ b/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/ChoiceGenerator.kt @@ -47,9 +47,9 @@ import io.spine.tools.validation.java.generate.ValidateScope.parentPath import io.spine.tools.validation.java.generate.ValidateScope.violations import io.spine.tools.validation.option.CHOICE import io.spine.validation.ConstraintViolation -import io.spine.validation.ErrorPlaceholder -import io.spine.validation.ErrorPlaceholder.GROUP_PATH -import io.spine.validation.ErrorPlaceholder.PARENT_TYPE +import io.spine.string.Placeholder +import io.spine.validation.StandardPlaceholder.GROUP_PATH +import io.spine.validation.StandardPlaceholder.PARENT_TYPE /** * The generator for the `(choice)` option. @@ -110,8 +110,8 @@ private class GenerateChoice(private val view: ChoiceOneof) { private fun supportedPlaceholders( groupPath: Expression, typeName: Expression, - ): Map> = mapOf( - GROUP_PATH to groupPath.joinToString(), - PARENT_TYPE to typeName + ): Map> = mapOf( + GROUP_PATH.value to groupPath.joinToString(), + PARENT_TYPE.value to typeName ) } diff --git a/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/DistinctGenerator.kt b/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/DistinctGenerator.kt index 7b98976c54..0107572201 100644 --- a/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/DistinctGenerator.kt +++ b/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/DistinctGenerator.kt @@ -61,12 +61,12 @@ import io.spine.tools.validation.java.generate.ValidateScope.parentPath import io.spine.tools.validation.java.generate.ValidateScope.violations import io.spine.tools.validation.option.PATTERN import io.spine.validation.ConstraintViolation -import io.spine.validation.ErrorPlaceholder -import io.spine.validation.ErrorPlaceholder.FIELD_DUPLICATES -import io.spine.validation.ErrorPlaceholder.FIELD_PATH -import io.spine.validation.ErrorPlaceholder.FIELD_TYPE -import io.spine.validation.ErrorPlaceholder.FIELD_VALUE -import io.spine.validation.ErrorPlaceholder.PARENT_TYPE +import io.spine.string.Placeholder +import io.spine.validation.StandardPlaceholder.FIELD_DUPLICATES +import io.spine.validation.StandardPlaceholder.FIELD_PATH +import io.spine.validation.StandardPlaceholder.FIELD_TYPE +import io.spine.validation.StandardPlaceholder.FIELD_VALUE +import io.spine.validation.StandardPlaceholder.PARENT_TYPE /** * The generator for the `(distinct)` option. @@ -179,11 +179,11 @@ private class GenerateDistinct(private val view: DistinctField) { typeName: Expression, fieldValue: Expression<*>, duplicates: Expression<*> - ): Map> = mapOf( - FIELD_PATH to fieldPath.joinToString(), - FIELD_VALUE to fieldType.stringValueOf(fieldValue), - FIELD_TYPE to StringLiteral(fieldType.name), - PARENT_TYPE to typeName, - FIELD_DUPLICATES to fieldType.stringValueOf(duplicates) + ): Map> = mapOf( + FIELD_PATH.value to fieldPath.joinToString(), + FIELD_VALUE.value to fieldType.stringValueOf(fieldValue), + FIELD_TYPE.value to StringLiteral(fieldType.name), + PARENT_TYPE.value to typeName, + FIELD_DUPLICATES.value to fieldType.stringValueOf(duplicates) ) } diff --git a/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/GoesGenerator.kt b/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/GoesGenerator.kt index 6f60ffed40..ffb046d3ac 100644 --- a/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/GoesGenerator.kt +++ b/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/GoesGenerator.kt @@ -53,12 +53,12 @@ import io.spine.tools.validation.java.generate.ValidateScope.parentPath import io.spine.tools.validation.java.generate.ValidateScope.violations import io.spine.tools.validation.option.GOES import io.spine.validation.ConstraintViolation -import io.spine.validation.ErrorPlaceholder -import io.spine.validation.ErrorPlaceholder.FIELD_PATH -import io.spine.validation.ErrorPlaceholder.FIELD_TYPE -import io.spine.validation.ErrorPlaceholder.FIELD_VALUE -import io.spine.validation.ErrorPlaceholder.GOES_COMPANION -import io.spine.validation.ErrorPlaceholder.PARENT_TYPE +import io.spine.string.Placeholder +import io.spine.validation.StandardPlaceholder.FIELD_PATH +import io.spine.validation.StandardPlaceholder.FIELD_TYPE +import io.spine.validation.StandardPlaceholder.FIELD_VALUE +import io.spine.validation.StandardPlaceholder.GOES_COMPANION +import io.spine.validation.StandardPlaceholder.PARENT_TYPE /** * The generator for the `(goes)` option. @@ -126,11 +126,11 @@ private class GenerateGoes( fieldPath: Expression, typeName: Expression, fieldValue: Expression<*>, - ): Map> = mapOf( - FIELD_PATH to fieldPath.joinToString(), - FIELD_VALUE to fieldType.stringValueOf(fieldValue), - FIELD_TYPE to StringLiteral(fieldType.name), - PARENT_TYPE to typeName, - GOES_COMPANION to StringLiteral(view.companion.name.value) + ): Map> = mapOf( + FIELD_PATH.value to fieldPath.joinToString(), + FIELD_VALUE.value to fieldType.stringValueOf(fieldValue), + FIELD_TYPE.value to StringLiteral(fieldType.name), + PARENT_TYPE.value to typeName, + GOES_COMPANION.value to StringLiteral(view.companion.name.value) ) } diff --git a/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/PatternGenerator.kt b/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/PatternGenerator.kt index 08efd5ede4..c247eeafb8 100644 --- a/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/PatternGenerator.kt +++ b/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/PatternGenerator.kt @@ -67,13 +67,13 @@ import io.spine.tools.validation.option.PATTERN import io.spine.tools.validation.option.isRepeatedString import io.spine.tools.validation.option.isSingularString import io.spine.validation.ConstraintViolation -import io.spine.validation.ErrorPlaceholder -import io.spine.validation.ErrorPlaceholder.FIELD_PATH -import io.spine.validation.ErrorPlaceholder.FIELD_TYPE -import io.spine.validation.ErrorPlaceholder.FIELD_VALUE -import io.spine.validation.ErrorPlaceholder.PARENT_TYPE -import io.spine.validation.ErrorPlaceholder.REGEX_MODIFIERS -import io.spine.validation.ErrorPlaceholder.REGEX_PATTERN +import io.spine.string.Placeholder +import io.spine.validation.StandardPlaceholder.FIELD_PATH +import io.spine.validation.StandardPlaceholder.FIELD_TYPE +import io.spine.validation.StandardPlaceholder.FIELD_VALUE +import io.spine.validation.StandardPlaceholder.PARENT_TYPE +import io.spine.validation.StandardPlaceholder.REGEX_MODIFIERS +import io.spine.validation.StandardPlaceholder.REGEX_PATTERN import java.util.regex.Matcher import java.util.regex.Pattern @@ -250,13 +250,13 @@ private class GeneratePattern(private val view: PatternField) { fieldPath: Expression, typeName: Expression, fieldValue: Expression, - ): Map> = mapOf( - FIELD_PATH to fieldPath.joinToString(), - FIELD_VALUE to fieldValue, - FIELD_TYPE to StringLiteral(fieldType.name), - PARENT_TYPE to typeName, - REGEX_PATTERN to StringLiteral(restoreProtobufEscapes(view.pattern)), - REGEX_MODIFIERS to StringLiteral(restoreProtobufEscapes("${view.modifier}")), + ): Map> = mapOf( + FIELD_PATH.value to fieldPath.joinToString(), + FIELD_VALUE.value to fieldValue, + FIELD_TYPE.value to StringLiteral(fieldType.name), + PARENT_TYPE.value to typeName, + REGEX_PATTERN.value to StringLiteral(restoreProtobufEscapes(view.pattern)), + REGEX_MODIFIERS.value to StringLiteral(restoreProtobufEscapes("${view.modifier}")), ) } diff --git a/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/RequireOptionGenerator.kt b/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/RequireOptionGenerator.kt index 2c2e29310d..0a31930e9b 100644 --- a/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/RequireOptionGenerator.kt +++ b/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/RequireOptionGenerator.kt @@ -50,9 +50,9 @@ import io.spine.tools.validation.java.generate.ValidateScope.violations import io.spine.tools.validation.java.generate.mangled import io.spine.tools.validation.option.REQUIRE import io.spine.validation.ConstraintViolation -import io.spine.validation.ErrorPlaceholder -import io.spine.validation.ErrorPlaceholder.MESSAGE_TYPE -import io.spine.validation.ErrorPlaceholder.REQUIRE_FIELDS +import io.spine.string.Placeholder +import io.spine.validation.StandardPlaceholder.MESSAGE_TYPE +import io.spine.validation.StandardPlaceholder.REQUIRE_FIELDS /** * The generator for the `(require)` option. @@ -141,9 +141,9 @@ private class GenerateRequire( return constraintViolation(errorMessage, typeNameStr, fieldPath = null, fieldValue = null) } - private fun supportedPlaceholders(): Map> = mapOf( - MESSAGE_TYPE to StringLiteral(view.id.qualifiedName), - REQUIRE_FIELDS to StringLiteral(view.specifiedGroups) + private fun supportedPlaceholders(): Map> = mapOf( + MESSAGE_TYPE.value to StringLiteral(view.id.qualifiedName), + REQUIRE_FIELDS.value to StringLiteral(view.specifiedGroups) ) private companion object { diff --git a/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/RequiredGenerator.kt b/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/RequiredGenerator.kt index 6e80f8a85f..478059be7b 100644 --- a/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/RequiredGenerator.kt +++ b/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/RequiredGenerator.kt @@ -50,10 +50,10 @@ import io.spine.tools.validation.java.generate.ValidateScope.parentPath import io.spine.tools.validation.java.generate.ValidateScope.violations import io.spine.tools.validation.option.IF_MISSING import io.spine.validation.ConstraintViolation -import io.spine.validation.ErrorPlaceholder -import io.spine.validation.ErrorPlaceholder.FIELD_PATH -import io.spine.validation.ErrorPlaceholder.FIELD_TYPE -import io.spine.validation.ErrorPlaceholder.PARENT_TYPE +import io.spine.string.Placeholder +import io.spine.validation.StandardPlaceholder.FIELD_PATH +import io.spine.validation.StandardPlaceholder.FIELD_TYPE +import io.spine.validation.StandardPlaceholder.PARENT_TYPE /** * The generator for `(required)` option. @@ -116,9 +116,9 @@ private class GenerateRequired( private fun supportedPlaceholders( fieldPath: Expression, typeName: Expression, - ): Map> = mapOf( - FIELD_PATH to fieldPath.joinToString(), - FIELD_TYPE to StringLiteral(field.type.name), - PARENT_TYPE to typeName + ): Map> = mapOf( + FIELD_PATH.value to fieldPath.joinToString(), + FIELD_TYPE.value to StringLiteral(field.type.name), + PARENT_TYPE.value to typeName ) } diff --git a/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/bound/BoundedFieldGenerator.kt b/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/bound/BoundedFieldGenerator.kt index e630732e1c..8b0b5b0f11 100644 --- a/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/bound/BoundedFieldGenerator.kt +++ b/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/bound/BoundedFieldGenerator.kt @@ -68,7 +68,7 @@ import io.spine.tools.validation.java.generate.option.bound.Docs.SCALAR_TYPES import io.spine.tools.validation.java.generate.option.bound.Docs.UNSIGNED_API import io.spine.type.TypeName import io.spine.validation.ConstraintViolation -import io.spine.validation.ErrorPlaceholder +import io.spine.string.Placeholder /** * An abstract base for field generators that restrict the range of numeric fields. @@ -170,7 +170,7 @@ internal abstract class BoundedFieldGenerator( fieldPath: Expression, typeName: Expression, fieldValue: Expression<*>, - ): Map> + ): Map> /** * Returns a number expression for this [NumericBound]. diff --git a/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/bound/MaxGenerator.kt b/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/bound/MaxGenerator.kt index f460c48716..de7f80b43c 100644 --- a/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/bound/MaxGenerator.kt +++ b/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/bound/MaxGenerator.kt @@ -44,13 +44,13 @@ import io.spine.tools.validation.java.expression.joinToString import io.spine.tools.validation.java.generate.OptionGenerator import io.spine.tools.validation.java.generate.SingleOptionCode import io.spine.tools.validation.option.MAX -import io.spine.validation.ErrorPlaceholder -import io.spine.validation.ErrorPlaceholder.FIELD_PATH -import io.spine.validation.ErrorPlaceholder.FIELD_TYPE -import io.spine.validation.ErrorPlaceholder.FIELD_VALUE -import io.spine.validation.ErrorPlaceholder.MAX_OPERATOR -import io.spine.validation.ErrorPlaceholder.MAX_VALUE -import io.spine.validation.ErrorPlaceholder.PARENT_TYPE +import io.spine.string.Placeholder +import io.spine.validation.StandardPlaceholder.FIELD_PATH +import io.spine.validation.StandardPlaceholder.FIELD_TYPE +import io.spine.validation.StandardPlaceholder.FIELD_VALUE +import io.spine.validation.StandardPlaceholder.MAX_OPERATOR +import io.spine.validation.StandardPlaceholder.MAX_VALUE +import io.spine.validation.StandardPlaceholder.PARENT_TYPE /** * The generator for the `(max)` option. @@ -101,12 +101,12 @@ private class GenerateMax(private val view: MaxField) : BoundedFieldGenerator(vi fieldPath: Expression, typeName: Expression, fieldValue: Expression<*>, - ): Map> = mapOf( - FIELD_PATH to fieldPath.joinToString(), - FIELD_VALUE to StringClass.call("valueOf", fieldValue), - FIELD_TYPE to StringLiteral(fieldType.name), - PARENT_TYPE to typeName, - MAX_VALUE to view.max.withFieldValue(bound), - MAX_OPERATOR to StringLiteral(if (isExclusive) "<" else "<=") + ): Map> = mapOf( + FIELD_PATH.value to fieldPath.joinToString(), + FIELD_VALUE.value to StringClass.call("valueOf", fieldValue), + FIELD_TYPE.value to StringLiteral(fieldType.name), + PARENT_TYPE.value to typeName, + MAX_VALUE.value to view.max.withFieldValue(bound), + MAX_OPERATOR.value to StringLiteral(if (isExclusive) "<" else "<=") ) } diff --git a/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/bound/MinGenerator.kt b/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/bound/MinGenerator.kt index 5d52805601..069b558e59 100644 --- a/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/bound/MinGenerator.kt +++ b/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/bound/MinGenerator.kt @@ -44,13 +44,13 @@ import io.spine.tools.validation.java.expression.joinToString import io.spine.tools.validation.java.generate.OptionGenerator import io.spine.tools.validation.java.generate.SingleOptionCode import io.spine.tools.validation.option.MIN -import io.spine.validation.ErrorPlaceholder -import io.spine.validation.ErrorPlaceholder.FIELD_PATH -import io.spine.validation.ErrorPlaceholder.FIELD_TYPE -import io.spine.validation.ErrorPlaceholder.FIELD_VALUE -import io.spine.validation.ErrorPlaceholder.MIN_OPERATOR -import io.spine.validation.ErrorPlaceholder.MIN_VALUE -import io.spine.validation.ErrorPlaceholder.PARENT_TYPE +import io.spine.string.Placeholder +import io.spine.validation.StandardPlaceholder.FIELD_PATH +import io.spine.validation.StandardPlaceholder.FIELD_TYPE +import io.spine.validation.StandardPlaceholder.FIELD_VALUE +import io.spine.validation.StandardPlaceholder.MIN_OPERATOR +import io.spine.validation.StandardPlaceholder.MIN_VALUE +import io.spine.validation.StandardPlaceholder.PARENT_TYPE /** * The generator for `(min)` option. @@ -101,12 +101,12 @@ private class GenerateMin(private val view: MinField) : BoundedFieldGenerator(vi fieldPath: Expression, typeName: Expression, fieldValue: Expression<*>, - ): Map> = mapOf( - FIELD_PATH to fieldPath.joinToString(), - FIELD_VALUE to StringClass.call("valueOf", fieldValue), - FIELD_TYPE to StringLiteral(fieldType.name), - PARENT_TYPE to typeName, - MIN_VALUE to view.min.withFieldValue(bound), - MIN_OPERATOR to StringLiteral(if (isExclusive) ">" else ">=") + ): Map> = mapOf( + FIELD_PATH.value to fieldPath.joinToString(), + FIELD_VALUE.value to StringClass.call("valueOf", fieldValue), + FIELD_TYPE.value to StringLiteral(fieldType.name), + PARENT_TYPE.value to typeName, + MIN_VALUE.value to view.min.withFieldValue(bound), + MIN_OPERATOR.value to StringLiteral(if (isExclusive) ">" else ">=") ) } diff --git a/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/bound/RangeGenerator.kt b/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/bound/RangeGenerator.kt index 72d257cc9f..96daca17e3 100644 --- a/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/bound/RangeGenerator.kt +++ b/java/src/main/kotlin/io/spine/tools/validation/java/generate/option/bound/RangeGenerator.kt @@ -45,12 +45,12 @@ import io.spine.tools.validation.java.expression.joinToString import io.spine.tools.validation.java.generate.OptionGenerator import io.spine.tools.validation.java.generate.SingleOptionCode import io.spine.tools.validation.option.RANGE -import io.spine.validation.ErrorPlaceholder -import io.spine.validation.ErrorPlaceholder.FIELD_PATH -import io.spine.validation.ErrorPlaceholder.FIELD_TYPE -import io.spine.validation.ErrorPlaceholder.FIELD_VALUE -import io.spine.validation.ErrorPlaceholder.PARENT_TYPE -import io.spine.validation.ErrorPlaceholder.RANGE_VALUE +import io.spine.string.Placeholder +import io.spine.validation.StandardPlaceholder.FIELD_PATH +import io.spine.validation.StandardPlaceholder.FIELD_TYPE +import io.spine.validation.StandardPlaceholder.FIELD_VALUE +import io.spine.validation.StandardPlaceholder.PARENT_TYPE +import io.spine.validation.StandardPlaceholder.RANGE_VALUE /** * The generator for `(range)` option. @@ -113,12 +113,12 @@ private class GenerateRange( fieldPath: Expression, typeName: Expression, fieldValue: Expression<*>, - ): Map> = mapOf( - FIELD_PATH to fieldPath.joinToString(), - FIELD_VALUE to StringClass.call("valueOf", fieldValue), - FIELD_TYPE to StringLiteral(fieldType.name), - PARENT_TYPE to typeName, - RANGE_VALUE to withFieldValue() + ): Map> = mapOf( + FIELD_PATH.value to fieldPath.joinToString(), + FIELD_VALUE.value to StringClass.call("valueOf", fieldValue), + FIELD_TYPE.value to StringLiteral(fieldType.name), + PARENT_TYPE.value to typeName, + RANGE_VALUE.value to withFieldValue() ) /** diff --git a/java/src/main/kotlin/io/spine/tools/validation/java/setonce/SetOnceConstraintViolation.kt b/java/src/main/kotlin/io/spine/tools/validation/java/setonce/SetOnceConstraintViolation.kt index b3edb1b465..2f33ed8d18 100644 --- a/java/src/main/kotlin/io/spine/tools/validation/java/setonce/SetOnceConstraintViolation.kt +++ b/java/src/main/kotlin/io/spine/tools/validation/java/setonce/SetOnceConstraintViolation.kt @@ -38,11 +38,12 @@ import io.spine.tools.validation.java.expression.constraintViolation import io.spine.tools.validation.java.expression.templateString import io.spine.tools.validation.option.IF_SET_AGAIN import io.spine.validation.ConstraintViolation -import io.spine.validation.ErrorPlaceholder.FIELD_PATH -import io.spine.validation.ErrorPlaceholder.FIELD_PROPOSED_VALUE -import io.spine.validation.ErrorPlaceholder.FIELD_TYPE -import io.spine.validation.ErrorPlaceholder.FIELD_VALUE -import io.spine.validation.ErrorPlaceholder.PARENT_TYPE +import io.spine.string.Placeholder +import io.spine.validation.StandardPlaceholder.FIELD_PATH +import io.spine.validation.StandardPlaceholder.FIELD_PROPOSED_VALUE +import io.spine.validation.StandardPlaceholder.FIELD_TYPE +import io.spine.validation.StandardPlaceholder.FIELD_VALUE +import io.spine.validation.StandardPlaceholder.PARENT_TYPE /** * Builds a [ConstraintViolation] instance for the given field. @@ -88,11 +89,11 @@ internal class SetOnceConstraintViolation( private fun supportedPlaceholders( currentValue: Expression, newValue: Expression - ) = mapOf( - FIELD_PATH to StringLiteral(fieldName), - FIELD_TYPE to StringLiteral(fieldType), - FIELD_VALUE to currentValue, - FIELD_PROPOSED_VALUE to newValue, - PARENT_TYPE to declaringType + ): Map> = mapOf( + FIELD_PATH.value to StringLiteral(fieldName), + FIELD_TYPE.value to StringLiteral(fieldType), + FIELD_VALUE.value to currentValue, + FIELD_PROPOSED_VALUE.value to newValue, + PARENT_TYPE.value to declaringType ) } diff --git a/jvm-runtime/build.gradle.kts b/jvm-runtime/build.gradle.kts index 1b839a3a32..d5aa9b8f6e 100644 --- a/jvm-runtime/build.gradle.kts +++ b/jvm-runtime/build.gradle.kts @@ -74,3 +74,5 @@ dependencies { } forceSpineBase() + +patchGeneratedTemplateString(upstreamTask = "generateProto") diff --git a/jvm-runtime/src/main/java/io/spine/validation/ViolationText.java b/jvm-runtime/src/main/java/io/spine/validation/ViolationText.java index 9c2e30e091..e9a4877d65 100644 --- a/jvm-runtime/src/main/java/io/spine/validation/ViolationText.java +++ b/jvm-runtime/src/main/java/io/spine/validation/ViolationText.java @@ -35,7 +35,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static io.spine.string.Diags.backtick; -import static io.spine.validation.TemplateStrings.format; +import static io.spine.string.TemplateStrings.format; import static java.lang.System.lineSeparator; import static java.util.stream.Collectors.joining; diff --git a/jvm-runtime/src/main/kotlin/io/spine/validation/DetectedViolation.kt b/jvm-runtime/src/main/kotlin/io/spine/validation/DetectedViolation.kt index 42629f82fe..ba6dc9846b 100644 --- a/jvm-runtime/src/main/kotlin/io/spine/validation/DetectedViolation.kt +++ b/jvm-runtime/src/main/kotlin/io/spine/validation/DetectedViolation.kt @@ -27,6 +27,7 @@ package io.spine.validation import io.spine.base.FieldPath +import io.spine.string.TemplateString /** * Abstract base for violations detected by [MessageValidator]s. diff --git a/jvm-runtime/src/main/kotlin/io/spine/validation/ErrorPlaceholder.kt b/jvm-runtime/src/main/kotlin/io/spine/validation/StandardPlaceholder.kt similarity index 59% rename from jvm-runtime/src/main/kotlin/io/spine/validation/ErrorPlaceholder.kt rename to jvm-runtime/src/main/kotlin/io/spine/validation/StandardPlaceholder.kt index f2a6bd5ad9..4696aea075 100644 --- a/jvm-runtime/src/main/kotlin/io/spine/validation/ErrorPlaceholder.kt +++ b/jvm-runtime/src/main/kotlin/io/spine/validation/StandardPlaceholder.kt @@ -26,8 +26,10 @@ package io.spine.validation +import io.spine.string.Placeholder + /** - * A template placeholder that can be used in error messages. + * The standard set of [Placeholder]s that can be used in error messages. * * Enumerates placeholder names that can be used within Protobuf definitions. * Each validation option declares the supported placeholders. Take a look at @@ -36,41 +38,41 @@ package io.spine.validation * The enum is used by the compiler model and Java renderer when validating and rendering * built-in option error messages. */ -public enum class ErrorPlaceholder(public val value: String) { +public enum class StandardPlaceholder(public val value: Placeholder) { // Common placeholders. - FIELD_PATH("field.path"), - FIELD_VALUE("field.value"), - FIELD_TYPE("field.type"), - MESSAGE_TYPE("message.type"), - PARENT_TYPE("parent.type"), + FIELD_PATH(Placeholder("field.path")), + FIELD_VALUE(Placeholder("field.value")), + FIELD_TYPE(Placeholder("field.type")), + MESSAGE_TYPE(Placeholder("message.type")), + PARENT_TYPE(Placeholder("parent.type")), // Placeholders for the field options. - REGEX_PATTERN("regex.pattern"), - REGEX_MODIFIERS("regex.modifiers"), - GOES_COMPANION("goes.companion"), - FIELD_PROPOSED_VALUE("field.proposed_value"), - FIELD_DUPLICATES("field.duplicates"), - RANGE_VALUE("range.value"), - MAX_VALUE("max.value"), - MAX_OPERATOR("max.operator"), - MIN_VALUE("min.value"), - MIN_OPERATOR("min.operator"), + REGEX_PATTERN(Placeholder("regex.pattern")), + REGEX_MODIFIERS(Placeholder("regex.modifiers")), + GOES_COMPANION(Placeholder("goes.companion")), + FIELD_PROPOSED_VALUE(Placeholder("field.proposed_value")), + FIELD_DUPLICATES(Placeholder("field.duplicates")), + RANGE_VALUE(Placeholder("range.value")), + MAX_VALUE(Placeholder("max.value")), + MAX_OPERATOR(Placeholder("max.operator")), + MIN_VALUE(Placeholder("min.value")), + MIN_OPERATOR(Placeholder("min.operator")), @Deprecated(message = "Use the placeholder reference from Spine Time instead.") - WHEN_IN("when.in"), + WHEN_IN(Placeholder("when.in")), // Placeholders for the `oneof` options. - GROUP_PATH("group.path"), + GROUP_PATH(Placeholder("group.path")), // Placeholder for the message options. - REQUIRE_FIELDS("require.fields"); + REQUIRE_FIELDS(Placeholder("require.fields")); - override fun toString(): String = value + /** + * The placeholder text as it appears in a template string (e.g., `${field.path}`). + * + * Shortcut for [value].[placed][Placeholder.placed]. + */ + public val placed: String + get() = value.placed } - -@Deprecated( - message = "Please use `ErrorPlaceholder` instead.", - replaceWith = ReplaceWith("ErrorPlaceholder") -) -public typealias RuntimeErrorPlaceholder = ErrorPlaceholder diff --git a/jvm-runtime/src/main/kotlin/io/spine/validation/TemplateStringExts.kt b/jvm-runtime/src/main/kotlin/io/spine/validation/TemplateStringExts.kt index d44d5335b8..3d9b79dc8f 100644 --- a/jvm-runtime/src/main/kotlin/io/spine/validation/TemplateStringExts.kt +++ b/jvm-runtime/src/main/kotlin/io/spine/validation/TemplateStringExts.kt @@ -24,106 +24,15 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -@file:JvmName("TemplateStrings") - package io.spine.validation import io.spine.code.proto.FieldDeclaration -import io.spine.validation.ErrorPlaceholder.FIELD_PATH -import io.spine.validation.ErrorPlaceholder.FIELD_TYPE -import io.spine.validation.ErrorPlaceholder.GOES_COMPANION -import io.spine.validation.ErrorPlaceholder.PARENT_TYPE -import io.spine.validation.ErrorPlaceholder.REGEX_PATTERN -import kotlin.collections.iterator - -/** - * Returns a template string with all placeholders substituted with - * their actual values. - * - * For example, for a template string with the following values: - * - * ``` - * with_placeholders = "My dog's name is ${dog.name}." - * placeholder_value = { "dog.name": "Fido" } - * ``` - * - * This method will return "My dog's name is Fido." - */ -public fun TemplateString.format(): String { - checkPlaceholdersHasValue(withPlaceholders, placeholderValueMap) { - "Cannot format the given `TemplateString`: `$withPlaceholders`. " + - "Missing value for the following placeholders: `$it`." - } - return formatUnsafe() -} - -/** - * Returns a template string with all placeholders substituted with - * their actual values, without validating that all placeholders have - * corresponding values. - * - * This method does not check whether every placeholder in the template has a matching value - * in the placeholder map. Any placeholders without a corresponding value will remain - * unchanged in the resulting string. - * - * For example, for a template string with the following values: - * - * ``` - * withPlaceholders = "My dog's name is ${dog.name} and its breed is ${dog.breed}." - * placeholderValue = { "dog.name": "Fido" } - * ``` - * - * This method will return "My dog's name is Fido and its breed is ${dog.breed}.". - */ -public fun TemplateString.formatUnsafe(): String { - var result = withPlaceholders - for ((key, value) in placeholderValueMap) { - result = result.replace("\${$key}", value) - } - return result -} - -/** - * Makes sure that each placeholder within the [template] string is present - * in the [placeholders] set. - * - * @param template The template with placeholders like `${something}`. - * @param placeholders The list with placeholder values. - * @param lazyMessage The message to use in [IllegalArgumentException] if the check fails. - */ -public fun checkPlaceholdersHasValue( - template: String, - placeholders: Set, - lazyMessage: (List) -> String = - { "Missing value for the following template placeholders: `$it`." } -) { - val neededPlaceholders = extractPlaceholders(template) - val missing = mutableListOf() - for (placeholder in neededPlaceholders) { - if (!placeholders.contains(placeholder)) { - missing.add(placeholder) - } - } - if (missing.isNotEmpty()) { - throw IllegalArgumentException(lazyMessage(missing)) - } -} - -/** - * Makes sure that each placeholder within the [template] string has a value - * in [placeholders] map. - * - * @param template The template with placeholders like `${something}`. - * @param placeholders The map containing placeholders (without curly braces and the dollar sign) - * and their values. - * @param lazyMessage The message to use in [IllegalArgumentException] if the check fails. - */ -public fun checkPlaceholdersHasValue( - template: String, - placeholders: Map, - lazyMessage: (List) -> String = - { "Missing value for the following template placeholders: `$it`." } -): Unit = checkPlaceholdersHasValue(template, placeholders.keys, lazyMessage) +import io.spine.string.TemplateString +import io.spine.validation.StandardPlaceholder.FIELD_PATH +import io.spine.validation.StandardPlaceholder.FIELD_TYPE +import io.spine.validation.StandardPlaceholder.GOES_COMPANION +import io.spine.validation.StandardPlaceholder.PARENT_TYPE +import io.spine.validation.StandardPlaceholder.REGEX_PATTERN /** * Fills in the fields-related placeholders from the given [field] declaration. @@ -135,28 +44,18 @@ public fun checkPlaceholdersHasValue( * 3. [PARENT_TYPE]. */ public fun TemplateString.Builder.withField(field: FieldDeclaration): TemplateString.Builder = - putPlaceholderValue(FIELD_PATH.value, field.name().value) - .putPlaceholderValue(FIELD_TYPE.value, field.javaTypeName()) - .putPlaceholderValue(PARENT_TYPE.value, field.declaringType().name().value) + putPlaceholderValue(FIELD_PATH.value.name, field.name().value) + .putPlaceholderValue(FIELD_TYPE.value.name, field.javaTypeName()) + .putPlaceholderValue(PARENT_TYPE.value.name, field.declaringType().name().value) /** * Fills in the value for [GOES_COMPANION] placeholder. */ public fun TemplateString.Builder.withCompanion(field: FieldDeclaration): TemplateString.Builder = - putPlaceholderValue(GOES_COMPANION.value, field.name().value) + putPlaceholderValue(GOES_COMPANION.value.name, field.name().value) /** * Fills in the value for [REGEX_PATTERN] placeholder. */ public fun TemplateString.Builder.withRegex(regex: String): TemplateString.Builder = - putPlaceholderValue(REGEX_PATTERN.value, regex) - -/** - * Extracts all placeholders used within this [template] string. - */ -public fun extractPlaceholders(template: String): Set = - PLACEHOLDERS.findAll(template) - .map { it.groupValues[1] } - .toSet() - -private val PLACEHOLDERS = Regex("\\$\\{([^}]+)}") + putPlaceholderValue(REGEX_PATTERN.value.name, regex) diff --git a/jvm-runtime/src/main/kotlin/io/spine/validation/TimestampValidator.kt b/jvm-runtime/src/main/kotlin/io/spine/validation/TimestampValidator.kt index b88a0ee4df..cfaf4b7141 100644 --- a/jvm-runtime/src/main/kotlin/io/spine/validation/TimestampValidator.kt +++ b/jvm-runtime/src/main/kotlin/io/spine/validation/TimestampValidator.kt @@ -32,8 +32,9 @@ import com.google.protobuf.util.Timestamps import com.google.protobuf.util.Timestamps.MAX_VALUE import com.google.protobuf.util.Timestamps.MIN_VALUE import io.spine.base.fieldPath -import io.spine.validation.ErrorPlaceholder.FIELD_PATH -import io.spine.validation.ErrorPlaceholder.RANGE_VALUE +import io.spine.string.templateString +import io.spine.validation.StandardPlaceholder.FIELD_PATH +import io.spine.validation.StandardPlaceholder.RANGE_VALUE /** * Validates [Timestamp] messages. @@ -66,10 +67,10 @@ public class TimestampValidator : MessageValidator { private fun invalidSeconds(seconds: Long): FieldViolation = FieldViolation( message = templateString { withPlaceholders = - "The ${FIELD_PATH.value} value is out of range" + - " (${RANGE_VALUE.value}): $seconds." - placeholderValue.put(FIELD_PATH.value, "seconds") - placeholderValue.put(RANGE_VALUE.value, + "The ${FIELD_PATH.value.name} value is out of range" + + " (${RANGE_VALUE.value.name}): $seconds." + placeholderValue.put(FIELD_PATH.value.name, "seconds") + placeholderValue.put(RANGE_VALUE.value.name, "${MIN_VALUE.seconds}..${MAX_VALUE.seconds}") }, @@ -84,10 +85,10 @@ private fun invalidSeconds(seconds: Long): FieldViolation = FieldViolation( */ private fun invalidNanos(nanos: Int): FieldViolation = FieldViolation( message = templateString { - withPlaceholders = "The ${FIELD_PATH.value} value is out of range" + - ": (${RANGE_VALUE.value})$nanos." - placeholderValue.put(FIELD_PATH.value, "nanos") - placeholderValue.put(RANGE_VALUE.value, "0..${MAX_VALUE.nanos}") + withPlaceholders = "The ${FIELD_PATH.value.name} value is out of range" + + ": (${RANGE_VALUE.value.name})$nanos." + placeholderValue.put(FIELD_PATH.value.name, "nanos") + placeholderValue.put(RANGE_VALUE.value.name, "0..${MAX_VALUE.nanos}") }, fieldPath = fieldPath { fieldName.add("nanos") diff --git a/jvm-runtime/src/main/kotlin/io/spine/validation/ValidatorRegistry.kt b/jvm-runtime/src/main/kotlin/io/spine/validation/ValidatorRegistry.kt index a7460bd348..02a114b292 100644 --- a/jvm-runtime/src/main/kotlin/io/spine/validation/ValidatorRegistry.kt +++ b/jvm-runtime/src/main/kotlin/io/spine/validation/ValidatorRegistry.kt @@ -33,6 +33,7 @@ import com.google.protobuf.Message import io.spine.annotation.VisibleForTesting import io.spine.base.FieldPath import io.spine.protobuf.TypeConverter +import io.spine.string.TemplateString import io.spine.type.TypeName import java.lang.reflect.ParameterizedType import java.util.* diff --git a/jvm-runtime/src/main/proto/spine/validation/error_message.proto b/jvm-runtime/src/main/proto/spine/validation/error_message.proto deleted file mode 100644 index 9521073f8c..0000000000 --- a/jvm-runtime/src/main/proto/spine/validation/error_message.proto +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2023, TeamDev. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -syntax = "proto3"; - -package spine.validation; - -import "spine/options.proto"; - -option (type_url_prefix) = "type.spine.io"; -option java_multiple_files = true; -option java_outer_classname = "ErrorMessageProto"; -option java_package = "io.spine.validation"; - -// Represents a template string with placeholders and a map for further substituting -// those placeholders with the actual values. -// -// Placeholders are specified using the format `${key}`, where `key` is the identifier -// for the value to be substituted from the `placeholder_value` map. There are no -// expectations about the identifier format. It can be `myKey`, `my.key`, `my_key`, etc. -// -// Example usage: -// template_string = "My dog's name is ${dog.name}." -// placeholder_values = { "dog.name": "Fido" } -// -// After substitution, the final output would be: -// "My dog's name is Fido." -// -// Each placeholder `key` referenced in the template string must have a corresponding entry -// in the `placeholder_value` map. However, the `placeholder_value` map is not restricted to -// containing only the placeholders used in the template. Additional entries in the map -// that do not correspond to placeholders in the template string are permitted. -// -message TemplateString { - - // The template string that may contain one or more placeholders. - string with_placeholders = 1; - - // A map that provides values for placeholders referenced in `with_placeholders`. - // - // The keys in this map should match the placeholder keys inside `with_placeholders` - // excluding the `${}` placeholder markers. - // - // All placeholders present in `with_placeholders` must have corresponding entries - // in this map. Otherwise, the template is considered invalid. - // - map placeholder_value = 2; -} diff --git a/jvm-runtime/src/main/proto/spine/validation/validation_error.proto b/jvm-runtime/src/main/proto/spine/validation/validation_error.proto index c9562d093e..cf0cb56e0b 100644 --- a/jvm-runtime/src/main/proto/spine/validation/validation_error.proto +++ b/jvm-runtime/src/main/proto/spine/validation/validation_error.proto @@ -36,7 +36,7 @@ option java_package = "io.spine.validation"; import "google/protobuf/any.proto"; -import "spine/validation/error_message.proto"; +import "spine/string/template_string.proto"; import "spine/base/field_path.proto"; // An error indicating that a message did not pass validation. @@ -60,9 +60,9 @@ message ConstraintViolation { // The returned message can be formatted using one of the following approaches: // // 1. In Kotlin, use the `TemplateString.format()` extension. - // 2. In Java, use the `io.spine.validate.TemplateStrings.format()` static method. + // 2. In Java, use the `io.spine.string.TemplateStrings.format()` static method. // - TemplateString message = 8; + spine.string.TemplateString message = 8; // The name of the validated message type. // diff --git a/jvm-runtime/src/test/kotlin/io/spine/validation/TemplateStringExtsSpec.kt b/jvm-runtime/src/test/kotlin/io/spine/validation/TemplateStringExtsSpec.kt deleted file mode 100644 index 9336eb3b94..0000000000 --- a/jvm-runtime/src/test/kotlin/io/spine/validation/TemplateStringExtsSpec.kt +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2024, TeamDev. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package io.spine.validation - -import io.kotest.matchers.shouldBe -import org.junit.jupiter.api.DisplayName -import org.junit.jupiter.api.Nested -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertDoesNotThrow -import org.junit.jupiter.api.assertThrows - -@DisplayName("`TemplateString` extensions should") -internal class TemplateStringExtsSpec { - - @Nested inner class - `format the template string` { - - @Test - fun `returning the correct result`() { - val template = templateString { - withPlaceholders = "My dog's name is \${dog.name}." - placeholderValue["dog.name"] = "Fido" - } - template.format() shouldBe "My dog's name is Fido." - } - - @Test - fun `returning an empty string if given an empty template`() { - TemplateString.getDefaultInstance().format() shouldBe "" - } - - @Test - fun `throwing when a placeholder has no value`() { - assertThrows { - val template = templateString { - withPlaceholders = "My dog's name is \${dog.name}." - } - template.format() - } - } - - @Test - fun `ignore when a placeholder with a value is not used`() { - assertDoesNotThrow { - val template = templateString { - withPlaceholders = "My dog's name is Fido." - placeholderValue["dog.name"] = "Fido" - } - template.format() - } - } - } - - @Nested inner class - `validate the template against placeholders` { - - private val message = { missingPlaceholders: List -> "$missingPlaceholders" } - private val template = "\${val1}, \${val2}, \${val3}, \${val4}, \${val5}" - private val fooPlaceholders = mapOf("val1" to "Foo", "val2" to "Foo", "val3" to "Foo") - private val barPlaceholders = mapOf("val4" to "Bar", "val5" to "Bar") - - @Test - fun `failing if the template has non-presentable placeholder`() { - val exception = assertThrows { - checkPlaceholdersHasValue(template, fooPlaceholders, message) - } - exception.message shouldBe message(listOf("val4", "val5")) - } - - @Test - fun `bypassing the template if all placeholders are present`() { - val placeholders = fooPlaceholders + barPlaceholders - assertDoesNotThrow { - checkPlaceholdersHasValue(template, placeholders, message) - } - } - } - - @Test - fun `format with missing placeholders`() { - val template = templateString { - withPlaceholders = "My dog's name is \${dog.name} and its breed is \${dog.breed}." - placeholderValue["dog.name"] = "Fido" - } - template.formatUnsafe() shouldBe "My dog's name is Fido and its breed is \${dog.breed}." - } -} diff --git a/jvm-runtime/src/test/kotlin/io/spine/validation/ValidatorRegistrySpec.kt b/jvm-runtime/src/test/kotlin/io/spine/validation/ValidatorRegistrySpec.kt index 8c9a2da8e1..a30319ba2a 100644 --- a/jvm-runtime/src/test/kotlin/io/spine/validation/ValidatorRegistrySpec.kt +++ b/jvm-runtime/src/test/kotlin/io/spine/validation/ValidatorRegistrySpec.kt @@ -32,6 +32,7 @@ import io.kotest.matchers.collections.shouldBeEmpty import io.kotest.matchers.collections.shouldContainExactly import io.kotest.matchers.collections.shouldHaveSize import io.kotest.matchers.shouldBe +import io.spine.string.templateString import java.util.ServiceLoader import java.util.concurrent.Executors import java.util.concurrent.TimeUnit diff --git a/jvm-runtime/src/test/kotlin/io/spine/validation/given/TemplateStrings.kt b/jvm-runtime/src/test/kotlin/io/spine/validation/given/TemplateStrings.kt index 24cc44202b..bd4bde29e2 100644 --- a/jvm-runtime/src/test/kotlin/io/spine/validation/given/TemplateStrings.kt +++ b/jvm-runtime/src/test/kotlin/io/spine/validation/given/TemplateStrings.kt @@ -26,8 +26,8 @@ package io.spine.validation.given -import io.spine.validation.TemplateString -import io.spine.validation.templateString +import io.spine.string.TemplateString +import io.spine.string.templateString /** * Creates a new [TemplateString] with the given [value], which does not diff --git a/settings.gradle.kts b/settings.gradle.kts index 95030fa624..84726e8fde 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -45,6 +45,7 @@ include( ":tests:consumer", ":tests:consumer-dependency", ":tests:runtime", + ":tests:time", ":tests:vanilla", ":tests:validating", ":tests:validator", diff --git a/tests/consumer/build.gradle.kts b/tests/consumer/build.gradle.kts index 87ce879e5f..694c18ced0 100644 --- a/tests/consumer/build.gradle.kts +++ b/tests/consumer/build.gradle.kts @@ -49,8 +49,12 @@ spine { dependencies { spineCompiler(project(":java")) - spineCompiler(project(":tests:extensions")) - implementation(project(":tests:extensions")) + @Suppress("AvoidDuplicateDependencies") // The subproject is used in different configurations. + run { + val testsExtensions = project(":tests:extensions") + spineCompiler(testsExtensions) + implementation(testsExtensions) + } implementation(project(":tests:consumer-dependency")) implementation(Time.lib) testImplementation(TestLib.lib) diff --git a/tests/consumer/src/test/kotlin/io/spine/validation/test/ErrorMessageSpec.kt b/tests/consumer/src/test/kotlin/io/spine/validation/test/ErrorMessageSpec.kt index 4172952c22..632480d81f 100644 --- a/tests/consumer/src/test/kotlin/io/spine/validation/test/ErrorMessageSpec.kt +++ b/tests/consumer/src/test/kotlin/io/spine/validation/test/ErrorMessageSpec.kt @@ -28,7 +28,7 @@ package io.spine.validation.test import io.kotest.matchers.shouldBe import io.spine.validation.ValidationException -import io.spine.validation.format +import io.spine.string.format import io.spine.tools.validation.test.money.Usd import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test diff --git a/tests/consumer/src/test/kotlin/io/spine/validation/test/MinRuleITest.kt b/tests/consumer/src/test/kotlin/io/spine/validation/test/MinRuleITest.kt index 55b04367e6..5537411398 100644 --- a/tests/consumer/src/test/kotlin/io/spine/validation/test/MinRuleITest.kt +++ b/tests/consumer/src/test/kotlin/io/spine/validation/test/MinRuleITest.kt @@ -27,7 +27,7 @@ package io.spine.validation.test import io.kotest.matchers.string.shouldContain -import io.spine.validation.format +import io.spine.string.format import io.spine.tools.validation.test.time.LocalTime import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test diff --git a/tests/consumer/src/test/kotlin/io/spine/validation/test/PatternRuleITest.kt b/tests/consumer/src/test/kotlin/io/spine/validation/test/PatternRuleITest.kt index bcd5bfe84c..eb1ecdd580 100644 --- a/tests/consumer/src/test/kotlin/io/spine/validation/test/PatternRuleITest.kt +++ b/tests/consumer/src/test/kotlin/io/spine/validation/test/PatternRuleITest.kt @@ -28,7 +28,7 @@ package io.spine.validation.test import com.google.common.truth.Truth.assertThat import io.kotest.matchers.shouldBe -import io.spine.validation.format +import io.spine.string.format import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test diff --git a/tests/consumer/src/test/kotlin/io/spine/validation/test/RequiredRuleITest.kt b/tests/consumer/src/test/kotlin/io/spine/validation/test/RequiredRuleITest.kt index 6545bac665..15ac03493a 100644 --- a/tests/consumer/src/test/kotlin/io/spine/validation/test/RequiredRuleITest.kt +++ b/tests/consumer/src/test/kotlin/io/spine/validation/test/RequiredRuleITest.kt @@ -28,8 +28,8 @@ package io.spine.validation.test import io.kotest.matchers.shouldBe import io.kotest.matchers.string.shouldContain -import io.spine.validation.format -import io.spine.validation.formatUnsafe +import io.spine.string.format +import io.spine.string.formatUnsafe import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test diff --git a/tests/consumer/src/test/kotlin/io/spine/validation/test/ValidateRuleITest.kt b/tests/consumer/src/test/kotlin/io/spine/validation/test/ValidateRuleITest.kt index 17caa2f166..023e8ea147 100644 --- a/tests/consumer/src/test/kotlin/io/spine/validation/test/ValidateRuleITest.kt +++ b/tests/consumer/src/test/kotlin/io/spine/validation/test/ValidateRuleITest.kt @@ -30,7 +30,7 @@ import com.google.protobuf.Message import io.kotest.matchers.string.shouldContain import io.spine.protobuf.AnyPacker import io.spine.protobuf.pack -import io.spine.validation.formatUnsafe +import io.spine.string.formatUnsafe import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test diff --git a/tests/extensions/src/main/kotlin/io/spine/tools/validation/test/CurrencyGenerator.kt b/tests/extensions/src/main/kotlin/io/spine/tools/validation/test/CurrencyGenerator.kt index 3bb66c66c2..ef1a2d4194 100644 --- a/tests/extensions/src/main/kotlin/io/spine/tools/validation/test/CurrencyGenerator.kt +++ b/tests/extensions/src/main/kotlin/io/spine/tools/validation/test/CurrencyGenerator.kt @@ -27,6 +27,7 @@ package io.spine.tools.validation.test import io.spine.server.query.select +import io.spine.string.Placeholder import io.spine.tools.compiler.ast.TypeName import io.spine.tools.compiler.jvm.CodeBlock import io.spine.tools.compiler.jvm.Expression @@ -36,7 +37,7 @@ import io.spine.tools.validation.java.expression.constraintViolation import io.spine.tools.validation.java.expression.orElse import io.spine.tools.validation.java.expression.stringValueOf import io.spine.tools.validation.java.expression.stringify -import io.spine.tools.validation.java.expression.withStringPlaceholders +import io.spine.tools.validation.java.expression.templateString import io.spine.tools.validation.java.generate.MessageScope.message import io.spine.tools.validation.java.generate.OptionGenerator import io.spine.tools.validation.java.generate.SingleOptionCode @@ -101,12 +102,12 @@ private class GenerateCurrency(private val view: CurrencyMessage) { ): Expression { val typeNameStr = typeName.stringify() val placeholders = supportedPlaceholders(minorValue) - val errorMessage = withStringPlaceholders(view.errorMessage, placeholders, CURRENCY) + val errorMessage = templateString(view.errorMessage, placeholders, CURRENCY) return constraintViolation(errorMessage, typeNameStr, fieldPath = null, fieldValue = null) } private fun supportedPlaceholders( minorValue: Expression - ): Map> = - mapOf("minor.value" to minorField.stringValueOf(minorValue)) + ): Map> = + mapOf(Placeholder("minor.value") to minorField.stringValueOf(minorValue)) } diff --git a/tests/runtime/src/test/kotlin/io/spine/validation/EnclosedMessageValidationSpec.kt b/tests/runtime/src/test/kotlin/io/spine/validation/EnclosedMessageValidationSpec.kt index dd57e1138a..678ed42476 100644 --- a/tests/runtime/src/test/kotlin/io/spine/validation/EnclosedMessageValidationSpec.kt +++ b/tests/runtime/src/test/kotlin/io/spine/validation/EnclosedMessageValidationSpec.kt @@ -27,6 +27,7 @@ package io.spine.validation import io.kotest.matchers.string.shouldContain +import io.spine.string.format import io.spine.test.validate.PatternStringFieldValue import io.spine.test.validate.ValidateEnclosed import io.spine.test.validate.ValidateWithRequiredString diff --git a/tests/runtime/src/test/kotlin/io/spine/validation/IfMissingErrorMsgSpec.kt b/tests/runtime/src/test/kotlin/io/spine/validation/IfMissingErrorMsgSpec.kt index 062a0211ce..659a6d11c8 100644 --- a/tests/runtime/src/test/kotlin/io/spine/validation/IfMissingErrorMsgSpec.kt +++ b/tests/runtime/src/test/kotlin/io/spine/validation/IfMissingErrorMsgSpec.kt @@ -30,6 +30,7 @@ import com.google.protobuf.Descriptors.Descriptor import com.google.protobuf.Message import io.kotest.matchers.shouldBe import io.spine.option.OptionsProto +import io.spine.string.format import io.spine.test.validate.CustomMessageRequiredByteStringFieldValue import io.spine.test.validate.CustomMessageRequiredEnumFieldValue import io.spine.test.validate.CustomMessageRequiredMsgFieldValue diff --git a/tests/runtime/src/test/kotlin/io/spine/validation/NumberRangeSpec.kt b/tests/runtime/src/test/kotlin/io/spine/validation/NumberRangeSpec.kt index 7286f5b8ae..284db0328e 100644 --- a/tests/runtime/src/test/kotlin/io/spine/validation/NumberRangeSpec.kt +++ b/tests/runtime/src/test/kotlin/io/spine/validation/NumberRangeSpec.kt @@ -29,6 +29,7 @@ package io.spine.validation import com.google.protobuf.Message import com.google.protobuf.doubleValue import io.kotest.matchers.string.shouldContain +import io.spine.string.format import io.spine.test.validate.MaxExclusive import io.spine.test.validate.MaxInclusive import io.spine.test.validate.MinExclusive diff --git a/tests/runtime/src/test/kotlin/io/spine/validation/ValidateUtilitySpec.kt b/tests/runtime/src/test/kotlin/io/spine/validation/ValidateUtilitySpec.kt index 27c7efae1a..0763c55f07 100644 --- a/tests/runtime/src/test/kotlin/io/spine/validation/ValidateUtilitySpec.kt +++ b/tests/runtime/src/test/kotlin/io/spine/validation/ValidateUtilitySpec.kt @@ -31,6 +31,7 @@ import com.google.protobuf.Message import io.kotest.matchers.shouldBe import io.spine.base.Time import io.spine.code.proto.FieldContext +import io.spine.string.templateString import io.spine.testing.UtilityClassTest import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test diff --git a/tests/runtime/src/test/kotlin/io/spine/validation/ValidationOfConstraintTest.kt b/tests/runtime/src/test/kotlin/io/spine/validation/ValidationOfConstraintTest.kt index 44a8b1d57f..2a0549e059 100644 --- a/tests/runtime/src/test/kotlin/io/spine/validation/ValidationOfConstraintTest.kt +++ b/tests/runtime/src/test/kotlin/io/spine/validation/ValidationOfConstraintTest.kt @@ -31,6 +31,7 @@ import com.google.protobuf.Message import io.kotest.matchers.collections.shouldHaveSize import io.kotest.matchers.shouldBe import io.kotest.matchers.string.shouldNotBeEmpty +import io.spine.string.format import io.spine.validation.Validate.violationsOf import org.junit.jupiter.api.Assertions.assertDoesNotThrow import org.junit.jupiter.api.assertThrows diff --git a/tests/runtime/src/test/kotlin/io/spine/validation/option/ChoiceSpec.kt b/tests/runtime/src/test/kotlin/io/spine/validation/option/ChoiceSpec.kt index 4e4116f1c3..293fdb65b5 100644 --- a/tests/runtime/src/test/kotlin/io/spine/validation/option/ChoiceSpec.kt +++ b/tests/runtime/src/test/kotlin/io/spine/validation/option/ChoiceSpec.kt @@ -37,7 +37,7 @@ import io.spine.testing.TestValues.randomString import io.spine.validation.ValidationException import io.spine.validation.ValidationOfConstraintTest import io.spine.validation.ValidationOfConstraintTest.Companion.VALIDATION_SHOULD -import io.spine.validation.format +import io.spine.string.format import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows diff --git a/tests/time/build.gradle.kts b/tests/time/build.gradle.kts new file mode 100644 index 0000000000..a3f37588ad --- /dev/null +++ b/tests/time/build.gradle.kts @@ -0,0 +1,71 @@ +/* + * Copyright 2026, TeamDev. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import io.spine.dependency.boms.BomsPlugin +import io.spine.dependency.local.Logging +import io.spine.dependency.local.TestLib +import io.spine.dependency.local.Time +import io.spine.gradle.report.license.LicenseReporter + +buildscript { + standardSpineSdkRepositories() + dependencies { + classpath(io.spine.dependency.local.Time.gradlePlugin) + } +} + +plugins { + java + `java-library` + kotlin("jvm") + id("module-testing") +} +apply(plugin = "io.spine.time") +apply() +LicenseReporter.generateReportIn(project) + +spine { + compiler { + plugins( + // Suppress warnings in the generated code. + "io.spine.tools.compiler.jvm.annotation.SuppressWarningsAnnotation\$Plugin", + "io.spine.validation.java.JavaValidationPlugin", + ) + } +} + +dependencies { + spineCompiler(project(":java")) + spineCompiler(Time.validation) + + implementation(Time.lib) + implementation(Time.javaExtensions) + + testImplementation(Logging.lib) + testImplementation(TestLib.lib) +} + +configureTaskDependencies() diff --git a/tests/time/src/test/kotlin/io/spine/test/validation/time/Assertions.kt b/tests/time/src/test/kotlin/io/spine/test/validation/time/Assertions.kt new file mode 100644 index 0000000000..a379e73d22 --- /dev/null +++ b/tests/time/src/test/kotlin/io/spine/test/validation/time/Assertions.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2026, TeamDev. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.test.validation.time + +import io.spine.validation.ValidationException +import org.junit.jupiter.api.assertDoesNotThrow +import org.junit.jupiter.api.assertThrows + +internal fun assertValidationFails(executable: () -> Unit) { + assertThrows { executable() } +} + +internal fun assertValidationPasses(executable: () -> Unit) { + assertDoesNotThrow(executable) +} diff --git a/tests/time/src/test/kotlin/io/spine/test/validation/time/Fixtures.kt b/tests/time/src/test/kotlin/io/spine/test/validation/time/Fixtures.kt new file mode 100644 index 0000000000..adb7a5bfbe --- /dev/null +++ b/tests/time/src/test/kotlin/io/spine/test/validation/time/Fixtures.kt @@ -0,0 +1,73 @@ +/* + * Copyright 2026, TeamDev. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.test.validation.time + +import com.google.protobuf.Timestamp +import com.google.protobuf.util.Durations.fromMillis +import com.google.protobuf.util.Timestamps +import io.spine.time.LocalDateTime +import io.spine.time.LocalDateTimes +import java.time.Instant +import java.time.LocalDateTime.ofInstant +import java.time.ZoneOffset.UTC + +/** + * Five hundred milliseconds. + * + * To shift the time into the past or future, we add or subtract a difference of this amount. + * + * There are two reasons for choosing 500 milliseconds: + * + * 1. The generated code uses `io.spine.base.Time.currentTime()` to get the current timestamp + * for comparison. In turn, this method relies on `io.spine.base.Time.SystemTimeProvider` + * by default, which has millisecond precision. + * 2. Adding too small an amount of time to make the stamp denote "future" might be unreliable. + * As it could catch up `now` by the time `Time.currentTime()` is invoked. + */ +private const val HALF_OF_SECOND: Long = 500 + +internal object TemporalFixtures { + + fun pastTime(): LocalDateTime { + val current = Instant.now() // It is a UTC stamp. + return LocalDateTimes.of(ofInstant(current.minusMillis(HALF_OF_SECOND), UTC)) + } + + fun futureTime(): LocalDateTime { + val current = Instant.now() // It is a UTC stamp. + return LocalDateTimes.of(ofInstant(current.plusMillis(HALF_OF_SECOND), UTC)) + } +} + +internal object TimestampFixtures { + + fun pastTime(): Timestamp = + Timestamps.subtract(Timestamps.now(), fromMillis(HALF_OF_SECOND)) + + fun futureTime(): Timestamp = + Timestamps.add(Timestamps.now(), fromMillis(HALF_OF_SECOND)) +} diff --git a/tests/time/src/test/kotlin/io/spine/test/validation/time/TemporalWhenSpec.kt b/tests/time/src/test/kotlin/io/spine/test/validation/time/TemporalWhenSpec.kt new file mode 100644 index 0000000000..5abe4eaec9 --- /dev/null +++ b/tests/time/src/test/kotlin/io/spine/test/validation/time/TemporalWhenSpec.kt @@ -0,0 +1,89 @@ +/* + * Copyright 2026, TeamDev. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.test.validation.time + +import io.spine.test.validation.time.TemporalFixtures.futureTime +import io.spine.test.validation.time.TemporalFixtures.pastTime +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test + +@DisplayName("If used with `Temporal`, `(when)` constraint should") +@Disabled("Until Spine Time migrates to the new Validation `Placeholder` API.") +internal class TemporalWhenSpec { + + @Nested inner class + `the past` { + + @Test + fun `throw, if restricted to be in future`() = assertValidationFails { + futureSpineTemporal { + value = pastTime() + } + } + + @Test + fun `pass, if restricted to be in past`() = assertValidationPasses { + pastSpineTemporal { + value = pastTime() + } + } + + @Test + fun `pass, if not restricted at all`() = assertValidationPasses { + anySpineTemporal { + value = pastTime() + } + } + } + + @Nested inner class + `the future` { + + @Test + fun `throw, if restricted to be in past`() = assertValidationFails { + pastSpineTemporal { + value = futureTime() + } + } + + @Test + fun `pass, if restricted to be in future`() = assertValidationPasses { + futureSpineTemporal { + value = futureTime() + } + } + + @Test + fun `pass, if not restricted at all`() = assertValidationPasses { + anySpineTemporal { + value = futureTime() + } + } + } +} diff --git a/tests/time/src/test/kotlin/io/spine/test/validation/time/TimestampWhenSpec.kt b/tests/time/src/test/kotlin/io/spine/test/validation/time/TimestampWhenSpec.kt new file mode 100644 index 0000000000..1a891b59eb --- /dev/null +++ b/tests/time/src/test/kotlin/io/spine/test/validation/time/TimestampWhenSpec.kt @@ -0,0 +1,93 @@ +/* + * Copyright 2026, TeamDev. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.test.validation.time + +import io.spine.test.validation.time.TimestampFixtures.futureTime +import io.spine.test.validation.time.TimestampFixtures.pastTime +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test + +@DisplayName("If used with Protobuf `Timestamp`, `(when)` constraint should") +@Disabled("Until Spine Time migrates to the new Validation `Placeholder` API.") +internal class TimestampWhenSpec { + + @Nested inner class + `when given a timestamp denoting` { + + @Nested inner class + `the past` { + + @Test + fun `throw, if restricted to be in future`() = assertValidationFails { + futureProtoTimestamp { + value = pastTime() + } + } + + @Test + fun `pass, if restricted to be in past`() = assertValidationPasses { + pastProtoTimestamp { + value = pastTime() + } + } + + @Test + fun `pass, if not restricted at all`() = assertValidationPasses { + anyProtoTimestamp { + value = pastTime() + } + } + } + + @Nested inner class + `the future` { + + @Test + fun `throw, if restricted to be in past`() = assertValidationFails { + pastProtoTimestamp { + value = futureTime() + } + } + + @Test + fun `pass, if restricted to be in future`() = assertValidationPasses { + futureProtoTimestamp { + value = futureTime() + } + } + + @Test + fun `pass, if not restricted at all`() = assertValidationPasses { + anyProtoTimestamp { + value = futureTime() + } + } + } + } +} diff --git a/tests/time/src/test/proto/spine/test/validation/time/when.proto b/tests/time/src/test/proto/spine/test/validation/time/when.proto new file mode 100644 index 0000000000..5136412a43 --- /dev/null +++ b/tests/time/src/test/proto/spine/test/validation/time/when.proto @@ -0,0 +1,70 @@ +/* + * Copyright 2026, TeamDev. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +syntax = "proto3"; + +package spine.test.validation.time; + +import "spine/options.proto"; +import "spine/time_options.proto"; + +option (type_url_prefix) = "type.spine.io"; +option java_package = "io.spine.test.validation.time"; +option java_outer_classname = "WhenProto"; +option java_multiple_files = true; + +import "google/protobuf/timestamp.proto"; +import "spine/time/time.proto"; + +// Tests `PAST` restriction with a Protobuf timestamp. +message PastProtoTimestamp { + google.protobuf.Timestamp value = 1 [(when).in = PAST]; +} + +// Tests `PAST` restriction with a Spine temporal. +message PastSpineTemporal { + spine.time.LocalDateTime value = 1 [(when).in = PAST]; +} + +// Tests `FUTURE` restriction with a Protobuf timestamp. +message FutureProtoTimestamp { + google.protobuf.Timestamp value = 1 [(when).in = FUTURE]; +} + +// Tests `FUTURE` restriction with a Spine temporal. +message FutureSpineTemporal { + spine.time.LocalDateTime value = 1 [(when).in = FUTURE]; +} + +// Tests that a Protobuf timestamp is not restricted when there's no option. +message AnyProtoTimestamp { + google.protobuf.Timestamp value = 1; +} + +// Tests that a Spine temporal is not restricted when there's no option. +message AnySpineTemporal { + spine.time.LocalDateTime value = 1; +} diff --git a/tests/validating/src/test/kotlin/io/spine/test/options/ChoiceITest.kt b/tests/validating/src/test/kotlin/io/spine/test/options/ChoiceITest.kt index a9f3713ad0..d45f4f4687 100644 --- a/tests/validating/src/test/kotlin/io/spine/test/options/ChoiceITest.kt +++ b/tests/validating/src/test/kotlin/io/spine/test/options/ChoiceITest.kt @@ -38,7 +38,7 @@ import io.spine.test.tools.validate.Sauce import io.spine.test.tools.validate.fish import io.spine.testing.TestValues.randomString import io.spine.validation.Validate.violationsOf -import io.spine.validation.format +import io.spine.string.format import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test diff --git a/tests/validating/src/test/kotlin/io/spine/test/options/NumberConstraintsITest.kt b/tests/validating/src/test/kotlin/io/spine/test/options/NumberConstraintsITest.kt index a9cf13ec4c..d97089968c 100644 --- a/tests/validating/src/test/kotlin/io/spine/test/options/NumberConstraintsITest.kt +++ b/tests/validating/src/test/kotlin/io/spine/test/options/NumberConstraintsITest.kt @@ -35,7 +35,7 @@ import io.spine.test.tools.validate.Probability import io.spine.test.tools.validate.SchoolClass import io.spine.test.tools.validate.Year import io.spine.test.tools.validate.targetMetrics -import io.spine.validation.format +import io.spine.string.format import io.spine.tools.validation.RangeFieldExtrema import io.spine.tools.validation.assertions.assertInvalid import io.spine.tools.validation.assertions.assertValid diff --git a/tests/validating/src/test/kotlin/io/spine/test/options/goes/GoesViolationITest.kt b/tests/validating/src/test/kotlin/io/spine/test/options/goes/GoesViolationITest.kt index 1653fe678e..720a7c62e4 100644 --- a/tests/validating/src/test/kotlin/io/spine/test/options/goes/GoesViolationITest.kt +++ b/tests/validating/src/test/kotlin/io/spine/test/options/goes/GoesViolationITest.kt @@ -36,11 +36,11 @@ import io.spine.test.options.set import io.spine.test.options.asPlaceholderValue import io.spine.test.tools.validate.GoesCustomMessage import io.spine.test.tools.validate.GoesDefaultMessage -import io.spine.validation.ErrorPlaceholder.FIELD_PATH -import io.spine.validation.ErrorPlaceholder.FIELD_TYPE -import io.spine.validation.ErrorPlaceholder.FIELD_VALUE -import io.spine.validation.ErrorPlaceholder.GOES_COMPANION -import io.spine.validation.ErrorPlaceholder.PARENT_TYPE +import io.spine.validation.StandardPlaceholder.FIELD_PATH +import io.spine.validation.StandardPlaceholder.FIELD_TYPE +import io.spine.validation.StandardPlaceholder.FIELD_VALUE +import io.spine.validation.StandardPlaceholder.GOES_COMPANION +import io.spine.validation.StandardPlaceholder.PARENT_TYPE import io.spine.validation.ValidationException import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.assertThrows @@ -94,11 +94,11 @@ private fun Builder.assertConstraintViolation( with(violation) { message.withPlaceholders shouldBe template(field.index + 1) message.placeholderValueMap shouldContainExactly mapOf( - FIELD_PATH to fieldName, - FIELD_VALUE to value.asPlaceholderValue(), - FIELD_TYPE to fieldType, - PARENT_TYPE to parentType, - GOES_COMPANION to COMPANION_FIELD, + FIELD_PATH.value to fieldName, + FIELD_VALUE.value to value.asPlaceholderValue(), + FIELD_TYPE.value to fieldType, + PARENT_TYPE.value to parentType, + GOES_COMPANION.value to COMPANION_FIELD, ).mapKeys { it.key.toString() } typeName shouldBe parentType diff --git a/tests/validating/src/test/kotlin/io/spine/test/options/required/RequireITest.kt b/tests/validating/src/test/kotlin/io/spine/test/options/required/RequireITest.kt index a71065bc6e..7e46af73c9 100644 --- a/tests/validating/src/test/kotlin/io/spine/test/options/required/RequireITest.kt +++ b/tests/validating/src/test/kotlin/io/spine/test/options/required/RequireITest.kt @@ -34,7 +34,7 @@ import io.spine.test.tools.validate.Citizen import io.spine.test.tools.validate.Due import io.spine.test.tools.validate.FieldGroup import io.spine.type.TypeName -import io.spine.validation.format +import io.spine.string.format import io.spine.tools.validation.assertions.assertInvalid import io.spine.tools.validation.assertions.assertValid import java.nio.charset.StandardCharsets.UTF_16 diff --git a/tests/validating/src/test/kotlin/io/spine/test/options/setonce/SetOnceViolationITest.kt b/tests/validating/src/test/kotlin/io/spine/test/options/setonce/SetOnceViolationITest.kt index 0b13cc33eb..0794b08bed 100644 --- a/tests/validating/src/test/kotlin/io/spine/test/options/setonce/SetOnceViolationITest.kt +++ b/tests/validating/src/test/kotlin/io/spine/test/options/setonce/SetOnceViolationITest.kt @@ -41,11 +41,11 @@ import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.assertThrows import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.MethodSource -import io.spine.validation.ErrorPlaceholder.FIELD_PATH -import io.spine.validation.ErrorPlaceholder.FIELD_PROPOSED_VALUE -import io.spine.validation.ErrorPlaceholder.FIELD_TYPE -import io.spine.validation.ErrorPlaceholder.FIELD_VALUE -import io.spine.validation.ErrorPlaceholder.PARENT_TYPE +import io.spine.validation.StandardPlaceholder.FIELD_PATH +import io.spine.validation.StandardPlaceholder.FIELD_PROPOSED_VALUE +import io.spine.validation.StandardPlaceholder.FIELD_TYPE +import io.spine.validation.StandardPlaceholder.FIELD_VALUE +import io.spine.validation.StandardPlaceholder.PARENT_TYPE /** * Tests [ConstraintViolation][io.spine.validation.ConstraintViolation]s created by `(set_once)`. @@ -100,11 +100,11 @@ private fun Builder.assertConstraintViolation( with(violation) { message.withPlaceholders shouldBe template(field.index + 1) message.placeholderValueMap shouldContainExactly mapOf( - FIELD_PATH to fieldName, - FIELD_TYPE to fieldType, - FIELD_VALUE to fieldValue1.asPlaceholderValue(), - FIELD_PROPOSED_VALUE to fieldValue2.asPlaceholderValue(), - PARENT_TYPE to parentType + FIELD_PATH.value to fieldName, + FIELD_TYPE.value to fieldType, + FIELD_VALUE.value to fieldValue1.asPlaceholderValue(), + FIELD_PROPOSED_VALUE.value to fieldValue2.asPlaceholderValue(), + PARENT_TYPE.value to parentType ).mapKeys { it.key.toString() } typeName shouldBe parentType diff --git a/tests/validating/src/testFixtures/kotlin/io/spine/tools/validation/assertions/Assertions.kt b/tests/validating/src/testFixtures/kotlin/io/spine/tools/validation/assertions/Assertions.kt index d3b142aaf2..7f44830cb3 100644 --- a/tests/validating/src/testFixtures/kotlin/io/spine/tools/validation/assertions/Assertions.kt +++ b/tests/validating/src/testFixtures/kotlin/io/spine/tools/validation/assertions/Assertions.kt @@ -37,7 +37,7 @@ import io.kotest.matchers.string.shouldContain import io.spine.type.toJson import io.spine.validation.ConstraintViolation import io.spine.validation.ValidationException -import io.spine.validation.formatUnsafe +import io.spine.string.formatUnsafe import org.junit.jupiter.api.Assertions.assertDoesNotThrow import org.junit.jupiter.api.Assertions.assertThrows import org.junit.jupiter.api.Assertions.fail diff --git a/tests/validator/src/main/kotlin/io/spine/tools/validation/test/EarphonesValidator.kt b/tests/validator/src/main/kotlin/io/spine/tools/validation/test/EarphonesValidator.kt index f275101f53..9168bb5a45 100644 --- a/tests/validator/src/main/kotlin/io/spine/tools/validation/test/EarphonesValidator.kt +++ b/tests/validator/src/main/kotlin/io/spine/tools/validation/test/EarphonesValidator.kt @@ -34,9 +34,9 @@ import io.spine.tools.validation.test.EarphonesValidator.Companion.ValidEarphone import io.spine.validation.DetectedViolation import io.spine.validation.FieldViolation import io.spine.validation.MessageValidator -import io.spine.validation.TemplateString +import io.spine.string.TemplateString import io.spine.validation.ValidatorRegistry -import io.spine.validation.templateString +import io.spine.string.templateString /** * Validates [Earphones] messages, treating all instances as invalid diff --git a/tests/validator/src/main/kotlin/io/spine/tools/validation/test/TheOnlyTimeValid.kt b/tests/validator/src/main/kotlin/io/spine/tools/validation/test/TheOnlyTimeValid.kt index 21921a2312..e5b4a0ee1d 100644 --- a/tests/validator/src/main/kotlin/io/spine/tools/validation/test/TheOnlyTimeValid.kt +++ b/tests/validator/src/main/kotlin/io/spine/tools/validation/test/TheOnlyTimeValid.kt @@ -35,9 +35,9 @@ import io.spine.base.fieldPath import io.spine.validation.DetectedViolation import io.spine.validation.FieldViolation import io.spine.validation.MessageValidator -import io.spine.validation.TemplateString +import io.spine.string.TemplateString import io.spine.validation.ValidatorRegistry -import io.spine.validation.templateString +import io.spine.string.templateString /** * Validates [com.google.protobuf.Timestamp] messages, treating all instances as invalid diff --git a/tests/vanilla/src/test/kotlin/io/spine/validation/java/IsRequiredSpec.kt b/tests/vanilla/src/test/kotlin/io/spine/validation/java/IsRequiredSpec.kt index 52dcda71b5..35e87a06aa 100644 --- a/tests/vanilla/src/test/kotlin/io/spine/validation/java/IsRequiredSpec.kt +++ b/tests/vanilla/src/test/kotlin/io/spine/validation/java/IsRequiredSpec.kt @@ -31,7 +31,7 @@ import com.google.protobuf.Message import io.spine.testing.TestValues.randomString import io.spine.validation.NonValidated import io.spine.validation.Validate.violationsOf -import io.spine.validation.format +import io.spine.string.format import io.spine.tools.validation.java.given.Fish import io.spine.tools.validation.java.given.Meal import io.spine.tools.validation.java.given.Sauce diff --git a/version.gradle.kts b/version.gradle.kts index 82a46bd6ca..335c9b3ba9 100644 --- a/version.gradle.kts +++ b/version.gradle.kts @@ -27,4 +27,4 @@ /** * The version of the Validation library to publish. */ -val validationVersion by extra("2.0.0-SNAPSHOT.421") +val validationVersion by extra("2.0.0-SNAPSHOT.430")