diff --git a/.agents/tasks/archive/built-in-options-plan.md b/.agents/tasks/archive/built-in-options-plan.md new file mode 100644 index 0000000000..c45e25385e --- /dev/null +++ b/.agents/tasks/archive/built-in-options-plan.md @@ -0,0 +1,75 @@ +# Task: Publish a reference set on built-in validation options + +## Goal + +Publish an actionable catalog of built-in *validation-related* options, organized by where +the option can be declared (field, `oneof`, message), and optimized for selecting the right +option for a use case. + +## Placement and structure + +- Placement: the "Built-in options" section comes after the "Concepts" section. +- Structure: implement "Built-in options" as a folder with a landing page and 4 child pages + (not a single long page). +- Avoid having a separate page per option. + +Proposed doc files under `docs/content/docs/validation/03-built-in-options/`: + +- `docs/content/docs/validation/03-built-in-options/_index.md` (landing page) +- `docs/content/docs/validation/03-built-in-options/field-level-options.md` + - Title: "Field-level options" +- `docs/content/docs/validation/03-built-in-options/oneof-fields.md` + - Title: "Options for `oneof` fields" +- `docs/content/docs/validation/03-built-in-options/message-level-options.md` + - Title: "Message-level options" +- `docs/content/docs/validation/03-built-in-options/repeated-and-map-fields.md` + - Title: "Options for `repeated` and `map` fields" + +Order of pages: exactly as listed above. + +## Scope and source of truth + +- Source of truth for what exists: `docs/_options/options.proto`. +- Scope: validation-related options only. + - Exclude non-validation options (API annotations, entity metadata, etc.). + - Exclude deprecated options (do not document them; do not add “deprecated catalogs”). +- Do not duplicate the full option documentation from `spine/options.proto`. + - Prefer short, “how to choose” descriptions, and link out for authoritative details. + +## Content principles (what each page should contain) + +Each page should: + +- Start with “When to use this page” and a small “Choose an option” list (use case → option). +- Group options by intent (presence, range, pattern, uniqueness, recursion, dependencies), + not by field number order. +- Include 1–2 minimal examples per group (copy-pasteable `.proto` snippets). +- Include “Applies to” and “Common combinations / gotchas” where the behavior is easy to + misunderstand (e.g., `(validate)` + default instances, uniqueness for collections, etc.). +- Link to `spine/options.proto` on GitHub when referencing the canonical definition. + +## What options to cover (high-level checklist) + +The catalog should cover (non-deprecated) validation-related options defined in +`docs/_options/options.proto`, including: + +- Field-level: + - Presence: `(required)`, `(if_missing)` + - Numeric constraints: `(min)`, `(max)`, `(range)` + - String/bytes constraints: `(pattern)` + - Nested validation: `(validate)` + - Cross-field dependency: `(goes)` + - Immutability: `(set_once)`, `(if_set_again)` + - Uniqueness for collections: `(distinct)`, `(if_has_duplicates)` +- `oneof`: + - Required selection: `(choice)` +- Message-level: + - Field-group requirements: `(require)` + +Note: keep this list aligned with `docs/_options/options.proto` and update it if the proto +changes. + +## External links + +- Link to canonical `spine/options.proto` where appropriate: + - https://github.com/SpineEventEngine/base-libraries/blob/master/base/src/main/proto/spine/options.proto diff --git a/.agents/tasks/built-in-options-plan.md b/.agents/tasks/built-in-options-plan.md deleted file mode 100644 index 90df03f04d..0000000000 --- a/.agents/tasks/built-in-options-plan.md +++ /dev/null @@ -1,7 +0,0 @@ -# Task: Publish a minimal reference set on built-in validation options -- Placement: a separate section coming after the "Concepts" section. -- From `docs/_options/options.proto`, - enumerate the built-in options and group them (fields, strings, numbers, collections, message-level). -- For each documented option: purpose, supported field types, common pitfalls, and a short `.proto` example. -- Start with the options already used in docs/examples: `(required)`, `(pattern)`, `(min)/(max)`, - `(distinct)`, `(validate)`. diff --git a/.agents/tasks/validation-documentation-plan.md b/.agents/tasks/validation-documentation-plan.md index 8152490abd..b84615806f 100644 --- a/.agents/tasks/validation-documentation-plan.md +++ b/.agents/tasks/validation-documentation-plan.md @@ -50,6 +50,7 @@ buildable documentation set, without expanding scope unnecessarily. - Status: DONE (2026-02-27). 5) [Built-in options](built-in-options-plan.md): publish a minimal reference set +- Status: DONE (2026-02-27). 6) [Validating third-party messages](third-party-messages-plan.md) diff --git a/dependencies.md b/dependencies.md index 7ce35d6304..93172c0ca6 100644 --- a/dependencies.md +++ b/dependencies.md @@ -1,6 +1,6 @@ -# Dependencies of `io.spine.tools:validation-context:2.0.0-SNAPSHOT.399` +# Dependencies of `io.spine.tools:validation-context:2.0.0-SNAPSHOT.400` ## Runtime 1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.20.0. @@ -1139,14 +1139,14 @@ The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Feb 26 22:11:03 WET 2026** using +This report was generated on **Fri Feb 27 20:33:13 WET 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.399` +# Dependencies of `io.spine.tools:validation-context-tests:2.0.0-SNAPSHOT.400` ## Runtime 1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.20.0. @@ -1731,7 +1731,7 @@ This report was generated on **Thu Feb 26 22:11:03 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Feb 26 22:11:02 WET 2026** using +This report was generated on **Fri Feb 27 20:33:12 WET 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). @@ -1752,7 +1752,7 @@ This report was generated on **Mon Feb 23 18:35:33 WET 2026** using -# Dependencies of `io.spine.tools:validation-gradle-plugin:2.0.0-SNAPSHOT.399` +# Dependencies of `io.spine.tools:validation-gradle-plugin:2.0.0-SNAPSHOT.400` ## Runtime 1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.20.0. @@ -2841,14 +2841,14 @@ This report was generated on **Mon Feb 23 18:35:33 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Feb 26 22:11:03 WET 2026** using +This report was generated on **Fri Feb 27 20:33:13 WET 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.399` +# Dependencies of `io.spine.tools:validation-java:2.0.0-SNAPSHOT.400` ## Runtime 1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.20.0. @@ -3935,14 +3935,14 @@ This report was generated on **Thu Feb 26 22:11:03 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Feb 26 22:11:03 WET 2026** using +This report was generated on **Fri Feb 27 20:33:13 WET 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.399` +# Dependencies of `io.spine.tools:validation-java-bundle:2.0.0-SNAPSHOT.400` ## Runtime 1. **Group** : com.google.auto.service. **Name** : auto-service-annotations. **Version** : 1.1.1. @@ -4005,14 +4005,14 @@ This report was generated on **Thu Feb 26 22:11:03 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Feb 26 22:11:01 WET 2026** using +This report was generated on **Fri Feb 27 20:33:11 WET 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:validation-jvm-runtime:2.0.0-SNAPSHOT.399` +# Dependencies of `io.spine:validation-jvm-runtime:2.0.0-SNAPSHOT.400` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -4845,14 +4845,14 @@ This report was generated on **Thu Feb 26 22:11:01 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Feb 26 22:11:03 WET 2026** using +This report was generated on **Fri Feb 27 20:33:13 WET 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-ksp:2.0.0-SNAPSHOT.399` +# Dependencies of `io.spine.tools:validation-ksp:2.0.0-SNAPSHOT.400` ## Runtime 1. **Group** : com.google.auto.service. **Name** : auto-service-annotations. **Version** : 1.1.1. @@ -5781,14 +5781,14 @@ This report was generated on **Thu Feb 26 22:11:03 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Feb 26 22:11:03 WET 2026** using +This report was generated on **Fri Feb 27 20:33:13 WET 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.399` +# Dependencies of `io.spine.tools:validation-consumer:2.0.0-SNAPSHOT.400` ## Runtime 1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.20.0. @@ -6379,14 +6379,14 @@ This report was generated on **Thu Feb 26 22:11:03 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Feb 26 22:11:01 WET 2026** using +This report was generated on **Fri Feb 27 20:33:12 WET 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.399` +# Dependencies of `io.spine.tools:validation-consumer-dependency:2.0.0-SNAPSHOT.400` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -6897,14 +6897,14 @@ This report was generated on **Thu Feb 26 22:11:01 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Feb 26 22:11:03 WET 2026** using +This report was generated on **Fri Feb 27 20:33:13 WET 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.399` +# Dependencies of `io.spine.tools:validation-extensions:2.0.0-SNAPSHOT.400` ## Runtime 1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.20.0. @@ -7588,14 +7588,14 @@ This report was generated on **Thu Feb 26 22:11:03 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Feb 26 22:11:03 WET 2026** using +This report was generated on **Fri Feb 27 20:33:12 WET 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.399` +# Dependencies of `io.spine.tools:validation-runtime:2.0.0-SNAPSHOT.400` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -8217,14 +8217,14 @@ This report was generated on **Thu Feb 26 22:11:03 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Feb 26 22:11:03 WET 2026** using +This report was generated on **Fri Feb 27 20:33:13 WET 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.399` +# Dependencies of `io.spine.tools:validation-validating:2.0.0-SNAPSHOT.400` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -8889,14 +8889,14 @@ This report was generated on **Thu Feb 26 22:11:03 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Feb 26 22:11:03 WET 2026** using +This report was generated on **Fri Feb 27 20:33:13 WET 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.399` +# Dependencies of `io.spine.tools:validation-validator:2.0.0-SNAPSHOT.400` ## Runtime 1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.20.0. @@ -9647,14 +9647,14 @@ This report was generated on **Thu Feb 26 22:11:03 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Feb 26 22:11:02 WET 2026** using +This report was generated on **Fri Feb 27 20:33:12 WET 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.399` +# Dependencies of `io.spine.tools:validation-validator-dependency:2.0.0-SNAPSHOT.400` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -9924,14 +9924,14 @@ This report was generated on **Thu Feb 26 22:11:02 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Feb 26 22:11:02 WET 2026** using +This report was generated on **Fri Feb 27 20:33:12 WET 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.399` +# Dependencies of `io.spine.tools:validation-vanilla:2.0.0-SNAPSHOT.400` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -10282,6 +10282,6 @@ This report was generated on **Thu Feb 26 22:11:02 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Feb 26 22:11:01 WET 2026** using +This report was generated on **Fri Feb 27 20:33:12 WET 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/_examples b/docs/_examples index 4d3727541f..57934013cb 160000 --- a/docs/_examples +++ b/docs/_examples @@ -1 +1 @@ -Subproject commit 4d3727541f0c4f771a6c1a215eef065cd3e74032 +Subproject commit 57934013cb7910c95f7926114d6c97c7be7329cd diff --git a/docs/_preview/package-lock.json b/docs/_preview/package-lock.json index c514573791..f2a2bed615 100644 --- a/docs/_preview/package-lock.json +++ b/docs/_preview/package-lock.json @@ -28,27 +28,6 @@ "postcss": "^8.0.0" } }, - "node_modules/@isaacs/balanced-match": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", - "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", - "dev": true, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@isaacs/brace-expansion": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", - "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", - "dev": true, - "dependencies": { - "@isaacs/balanced-match": "^4.0.1" - }, - "engines": { - "node": "20 || >=22" - } - }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -219,6 +198,16 @@ "postcss": "^8.1.0" } }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, "node_modules/baseline-browser-mapping": { "version": "2.8.31", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.31.tgz", @@ -240,6 +229,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, "node_modules/braces": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", @@ -657,15 +659,16 @@ } }, "node_modules/minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" + "brace-expansion": "^5.0.2" }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" diff --git a/docs/content/docs/validation/01-getting-started/adding-to-build.md b/docs/content/docs/validation/01-getting-started/adding-to-build.md index 8a3026ca63..06205c6dea 100644 --- a/docs/content/docs/validation/01-getting-started/adding-to-build.md +++ b/docs/content/docs/validation/01-getting-started/adding-to-build.md @@ -82,7 +82,7 @@ Add the Validation plugin to the build. ```kotlin plugins { module - id("io.spine.validation") version "2.0.0-SNAPSHOT.399" + id("io.spine.validation") version "2.0.0-SNAPSHOT.400" } ``` diff --git a/docs/content/docs/validation/03-built-in-options/_index.md b/docs/content/docs/validation/03-built-in-options/_index.md index 6e186d9a85..0559f82d32 100644 --- a/docs/content/docs/validation/03-built-in-options/_index.md +++ b/docs/content/docs/validation/03-built-in-options/_index.md @@ -6,7 +6,45 @@ headline: Documentation # Built-in options -## What’s next +{{% note-block class="lead" %}} +This section is a “how to choose” catalog of the **built-in validation options** +from `spine/options.proto`. + +It focuses on the options that affect **Spine Validation** and skips deprecated and +non-validation options. +{{% /note-block %}} + +## When to use this section + +Use this section when you want to: + +- pick the right option for a specific validation need, like presence, bounds, uniqueness, etc.; +- understand where an option can be declared (field, `oneof`, message); +- see minimal `.proto` snippets you can copy into a model. + +## Choose a page +- **Most field constraints** — presence, bounds, patterns, nested validation, dependencies: + [Field-level options](field-level-options.md) +- **Enforce “one of these fields must be set” in a `oneof`:** + [Options for `oneof` fields](oneof-fields.md) +- **Cross-field rules on a message (“at least one group is set”):** + [Message-level options](message-level-options.md) +- **Collections (`repeated` / `map`) — non-empty, uniqueness, per-element validation:** + [Options for `repeated` and `map` fields](repeated-and-map-fields.md) + +## Source of truth + +This catalog is based on the non-deprecated, validation-related options defined in +[spine/options.proto](https://github.com/SpineEventEngine/base-libraries/blob/master/base/src/main/proto/spine/options.proto). + +For the canonical option definitions, see `spine/options.proto` in the Spine base libraries +on GitHub: [spine/options.proto](https://github.com/SpineEventEngine/base-libraries/blob/master/base/src/main/proto/spine/options.proto). + +## What’s next +- [Field-level options](field-level-options.md) +- [Options for `oneof` fields](oneof-fields.md) +- [Message-level options](message-level-options.md) +- [Options for `repeated` and `map` fields](repeated-and-map-fields.md) - [Validating third-party messages](../04-third-party-messages/) - [Custom validation](../08-custom-validation/) diff --git a/docs/content/docs/validation/03-built-in-options/field-level-options.md b/docs/content/docs/validation/03-built-in-options/field-level-options.md new file mode 100644 index 0000000000..8fe8703497 --- /dev/null +++ b/docs/content/docs/validation/03-built-in-options/field-level-options.md @@ -0,0 +1,187 @@ +--- +title: Field-level options +description: How to choose built-in validation options applied to fields. +headline: Documentation +weight: 10 +--- + +# Field-level options + +{{% note-block class="lead" %}} +Use this page when you want to validate a field by declaring options next to it in a `.proto` file. +{{% /note-block %}} + +## Choose an option + +- Require a value to be present: `(required)`, customize with `(if_missing).error_msg` +- Enforce a numeric boundary: `(min)`, `(max)`, or `(range)` +- Enforce a string format: `(pattern).regex` +- Validate a nested message: `(validate) = true` +- Require another field when this one is set: `(goes).with = "other_field"` +- Prevent reassignment: `(set_once) = true`, customize with `(if_set_again).error_msg` + +For canonical definitions, see +[spine/options.proto](https://github.com/SpineEventEngine/base-libraries/blob/master/base/src/main/proto/spine/options.proto). + +## Presence: `(required)` and `(if_missing)` + +Use `(required)` when a field must not be “unset” for its type. + +**Applies to** + +- Message and enum fields (must be non-default). +- `string` / `bytes` fields (must be non-empty). +- Collections (`repeated` / `map`) (must be non-empty; see also + [Options for `repeated` and `map` fields](repeated-and-map-fields.md)). + +**Minimal example** + +```protobuf +import "spine/options.proto"; + +message UserEmail { + string value = 1 [(required) = true]; +} +``` + +**Custom message** + +```protobuf +import "spine/options.proto"; + +message Student { + string id = 1 [ + (required) = true, + (if_missing).error_msg = "Student ID must be set." + ]; +} +``` + +## Numeric constraints + +Use `(min)`, `(max)`, and `(range)` when a numeric value must fall within a bound. + +**Applies to** + +- Singular numeric fields. +- `repeated` numeric fields — each element is checked. + +### Choose between `(min)` / `(max)` and `(range)` + +- Use `(min)` / `(max)` for **unbounded** ranges (for example, “`>= 0`”). +- Use `(range)` for a **bounded** interval in one option. + +**Minimal example** + +```protobuf +import "spine/options.proto"; + +message Temperature { + int32 kelvin = 1 [(min).value = "0"]; +} +``` + +**Bounded range** + +```protobuf +import "spine/options.proto"; + +message Percent { + int32 value = 1 [(range).value = "[0..100]"]; +} +``` + +## Patterns: `(pattern)` + +Use `(pattern).regex` when a `string` must match a regular expression. + +**Applies to** + +- Singular `string` fields. +- `repeated string` fields — each element is checked. + +**Minimal example** + +```protobuf +import "spine/options.proto"; + +message OrderId { + string value = 1 [(pattern).regex = "^[A-Z]{3}-\\d{6}$"]; +} +``` + +## Nested validation: `(validate)` + +Use `(validate) = true` when a field refers to another **message type** and you want to enforce +the nested message’s own constraints. + +**Applies to** + +- Singular message fields. +- Repeated fields of message type. +- Map fields with message values. + +**Common gotcha: default instances** + +For **singular** message fields, default instances are treated like “no value set”, even when +`(validate) = true`. If you want to reject default instances, make the field required. + +```protobuf +import "spine/options.proto"; + +message Address { + string value = 1 [(required) = true]; +} + +message Student { + Address address = 1 [(validate) = true, (required) = true]; +} +``` + +## Cross-field dependency: `(goes)` + +Use `(goes).with = "companion"` when this field is only valid if another field is also set. + +**Applies to** + +- Message and enum fields. +- `string` / `bytes` fields. +- Collections (`repeated` / `map`). + +**Minimal example** + +```protobuf +import "spine/options.proto"; + +message ScheduledItem { + string date = 1; + string time = 2 [(goes).with = "date"]; +} +``` + +## Single assignment: `(set_once)` and `(if_set_again)` + +Use `(set_once) = true` when a field must be assigned at most once, for example, a permanent ID. + +**Applies to** + +- Singular fields of supported scalar, enum, and message types. + +**Does not apply to** + +- `repeated` / `map` fields. +- Fields with explicit `optional` cardinality. + +**Minimal example** + +```protobuf +import "spine/options.proto"; + +message UserId { + string value = 1 [(required) = true]; +} + +message User { + UserId id = 1 [(set_once) = true]; +} +``` diff --git a/docs/content/docs/validation/03-built-in-options/message-level-options.md b/docs/content/docs/validation/03-built-in-options/message-level-options.md new file mode 100644 index 0000000000..142371ebe6 --- /dev/null +++ b/docs/content/docs/validation/03-built-in-options/message-level-options.md @@ -0,0 +1,54 @@ +--- +title: Message-level options +description: How to express validation rules that depend on multiple fields. +headline: Documentation +weight: 30 +--- + +# Message-level options + +{{% note-block class="lead" %}} +Use this page when message validity depends on **multiple fields together**, such as: + +- “At least one of these fields must be set.” +- “Either this group of fields is set, or that group is set.” +{{% /note-block %}} + + +For canonical definitions, see +[spine/options.proto](https://github.com/SpineEventEngine/base-libraries/blob/master/base/src/main/proto/spine/options.proto). + +## Field group requirements: `(require)` + +Use `option (require).fields` on a message to declare **alternative groups** of required fields. + +**How to write the expression** + +- Use `|` to separate alternative groups. +- Use `&` inside a group to require multiple fields together. +- You can use `oneof` group names as operands in combination with + the [`(choice)`](oneof-fields.md) option. + +**Applies to** + +- Message types (declared as a message option). + +**Minimal example** + +```protobuf +import "spine/options.proto"; + +message PersonName { + option (require).fields = "given_name | honorific_prefix & family_name"; + + string honorific_prefix = 1; + string given_name = 2; + string family_name = 3; +} +``` + +## Common gotchas + +- This option works only with field types where “set” is well-defined: messages/enums + (non-default), `string`/`bytes` (non-empty), and collections (non-empty). If you need a similar + rule for scalars, wrap the scalar into a message or use a `oneof`. diff --git a/docs/content/docs/validation/03-built-in-options/oneof-fields.md b/docs/content/docs/validation/03-built-in-options/oneof-fields.md new file mode 100644 index 0000000000..57d7993e8c --- /dev/null +++ b/docs/content/docs/validation/03-built-in-options/oneof-fields.md @@ -0,0 +1,46 @@ +--- +title: Options for `oneof` fields +description: How to enforce selection rules for `oneof` groups. +headline: Documentation +weight: 20 +--- + +# Options for `oneof` fields + +{{% note-block class="lead" %}} +Use this page when you have a `oneof` group and want to enforce that **one of its cases is set**. +{{% /note-block %}} + +For canonical definitions, see +[spine/options.proto](https://github.com/SpineEventEngine/base-libraries/blob/master/base/src/main/proto/spine/options.proto). + +## Required selection: `(choice)` + +Use `(choice).required = true` on a `oneof` group to require selecting one of its fields. + +**Applies to** + +- `oneof` groups (declared on the `oneof` itself, not on a field inside it). + +**Minimal example** + +```protobuf +import "spine/options.proto"; + +message Contact { + oneof channel { + option (choice).required = true; + + string email = 1; + string phone = 2; + } +} +``` + +## Common combinations / gotchas + +- Use `(choice)` for the group, and apply field-level constraints (like `(pattern)` or + `(required)`) to individual cases when needed. +- If the requirement is “at least one of these fields OR one of these other fields”, use + [Message-level options](message-level-options.md) with `(require).fields` and include `oneof` + group names. diff --git a/docs/content/docs/validation/03-built-in-options/repeated-and-map-fields.md b/docs/content/docs/validation/03-built-in-options/repeated-and-map-fields.md new file mode 100644 index 0000000000..9ac6442b4b --- /dev/null +++ b/docs/content/docs/validation/03-built-in-options/repeated-and-map-fields.md @@ -0,0 +1,114 @@ +--- +title: Options for `repeated` and `map` fields +description: How to choose built-in validation options for collections. +headline: Documentation +weight: 40 +--- + +# Options for `repeated` and `map` fields + +{{% note-block class="lead" %}} +Use this page when you want to validate **collections** declared as `repeated` fields +or `map` fields. +{{% /note-block %}} + +## Choose an option + +- Require a collection to be non-empty: `(required) = true` +- Enforce uniqueness: `(distinct) = true`, customize with `(if_has_duplicates).error_msg` +- Validate nested message elements/values: `(validate) = true` +- Enforce numeric constraints per element: `(min)`, `(max)`, `(range)` +- Enforce a pattern per element: `(pattern).regex` +- Require a companion field when the collection is present: `(goes).with = "other_field"` + +For canonical definitions, see +[spine/options.proto](https://github.com/SpineEventEngine/base-libraries/blob/master/base/src/main/proto/spine/options.proto). + +## Presence: `(required)` + +Use `(required) = true` when a `repeated` field or a `map` must contain **at least one element**. + +```protobuf +import "spine/options.proto"; + +message Team { + repeated string members = 1 [(required) = true]; +} +``` + +## Uniqueness: `(distinct)` and `(if_has_duplicates)` + +Use `(distinct) = true` when all elements in a collection must be unique. + +**Applies to** + +- `repeated` fields — elements must be unique. +- `map` fields — values must be unique; keys are already unique by Protobuf rules. + +**Minimal example** + +```protobuf +import "spine/options.proto"; + +message Labels { + repeated string value = 1 [(distinct) = true]; +} +``` + +**Map values** + +```protobuf +import "spine/options.proto"; + +message Emails { + map by_type = 1 [(distinct) = true]; +} +``` + +**Common gotcha** + +Uniqueness is checked by full element equality, for example, `equals()` in Java. +If you need “unique by ID”, model the ID as the element itself, or use a `map` keyed by the ID. + +## Nested validation: `(validate)` for elements and map values + +Use `(validate) = true` when collection elements (or map values) are messages and must satisfy +their own constraints. + +```protobuf +import "spine/options.proto"; + +message PhoneNumber { + string value = 1 [(required) = true, (pattern).regex = "^\\+?[0-9\\s\\-()]{1,30}$"]; +} + +message ContactBook { + repeated PhoneNumber number = 1 [(validate) = true]; +} +``` + +## Per-element value constraints + +### Numeric options: `(min)`, `(max)`, `(range)` + +Use numeric constraints on `repeated` numeric fields to validate each element. + +```protobuf +import "spine/options.proto"; + +message Measurements { + repeated int32 sample = 1 [(min).value = "0", (max).value = "100"]; +} +``` + +### String patterns: `(pattern)` + +Use `(pattern)` on `repeated string` fields to validate each element. + +```protobuf +import "spine/options.proto"; + +message Tags { + repeated string value = 1 [(pattern).regex = "^[a-z0-9-]{1,32}$"]; +} +``` diff --git a/docs/data/docs/validation/2-0-0-snapshot/sidenav.yml b/docs/data/docs/validation/2-0-0-snapshot/sidenav.yml index 907ffec735..6c910b386a 100644 --- a/docs/data/docs/validation/2-0-0-snapshot/sidenav.yml +++ b/docs/data/docs/validation/2-0-0-snapshot/sidenav.yml @@ -36,7 +36,18 @@ - page: Working with error messages file_path: 02-concepts/error-messages - page: Built-in options - file_path: 03-built-in-options + key: 03-built-in-options + children: + - page: Built-in options + file_path: 03-built-in-options + - page: Field-level options + file_path: 03-built-in-options/field-level-options + - page: "Options for `oneof` fields" + file_path: 03-built-in-options/oneof-fields + - page: Message-level options + file_path: 03-built-in-options/message-level-options + - page: "Options for `repeated` and `map` fields" + file_path: 03-built-in-options/repeated-and-map-fields - page: Validating third-party messages file_path: 04-third-party-messages - page: Custom validation diff --git a/pom.xml b/pom.xml index ed86aa7649..84c66423bc 100644 --- a/pom.xml +++ b/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.399 +2.0.0-SNAPSHOT.400 2015 diff --git a/version.gradle.kts b/version.gradle.kts index 8b272b178d..197951b0e1 100644 --- a/version.gradle.kts +++ b/version.gradle.kts @@ -29,4 +29,4 @@ * * For Spine-based dependencies please see [io.spine.dependency.local.Spine]. */ -val validationVersion by extra("2.0.0-SNAPSHOT.399") +val validationVersion by extra("2.0.0-SNAPSHOT.400")