From 6dc7a0941b2cba7ca4f2269756b5175fe98c04f8 Mon Sep 17 00:00:00 2001
From: Sebastian Toepfer <61313468+sebastian-toepfer@users.noreply.github.com>
Date: Mon, 2 Dec 2024 21:43:58 +0100
Subject: [PATCH] add format assertion for dates,times and duration
---
pom.xml | 3 +-
vocabulary/format-assertion/pom.xml | 78 +++++++++++++++
.../FormatAssertionKeyWordType.java | 49 ++++++++++
.../FormatAssertionVocabulary.java | 69 +++++++++++++
.../formatassertion/FormatKeyword.java | 74 ++++++++++++++
.../vocabulary/formatassertion/Formats.java | 96 +++++++++++++++++++
.../formatassertion/rfc/RegExRule.java | 41 ++++++++
.../vocabulary/formatassertion/rfc/Rfc.java | 30 ++++++
.../formatassertion/rfc/Rfc3339.java | 59 ++++++++++++
.../vocabulary/formatassertion/rfc/Rule.java | 28 ++++++
.../src/main/java/module-info.java | 33 +++++++
.../src/main/resources/rfc/rfc3339 | 30 ++++++
.../FormatAssertionKeyWordTypeTest.java | 50 ++++++++++
.../FormatAssertionVocabularyTest.java | 64 +++++++++++++
.../formatassertion/FormatKeywordTest.java | 89 +++++++++++++++++
.../formatassertion/FormatsTest.java | 62 ++++++++++++
.../src/test/java/module-info.java | 38 ++++++++
vocabulary/pom.xml | 22 +++++
18 files changed, 914 insertions(+), 1 deletion(-)
create mode 100644 vocabulary/format-assertion/pom.xml
create mode 100644 vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatAssertionKeyWordType.java
create mode 100644 vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatAssertionVocabulary.java
create mode 100644 vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatKeyword.java
create mode 100644 vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/Formats.java
create mode 100644 vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/rfc/RegExRule.java
create mode 100644 vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/rfc/Rfc.java
create mode 100644 vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/rfc/Rfc3339.java
create mode 100644 vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/rfc/Rule.java
create mode 100644 vocabulary/format-assertion/src/main/java/module-info.java
create mode 100644 vocabulary/format-assertion/src/main/resources/rfc/rfc3339
create mode 100644 vocabulary/format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatAssertionKeyWordTypeTest.java
create mode 100644 vocabulary/format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatAssertionVocabularyTest.java
create mode 100644 vocabulary/format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatKeywordTest.java
create mode 100644 vocabulary/format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatsTest.java
create mode 100644 vocabulary/format-assertion/src/test/java/module-info.java
create mode 100644 vocabulary/pom.xml
diff --git a/pom.xml b/pom.xml
index 81edb15..b0eb8fe 100644
--- a/pom.xml
+++ b/pom.xml
@@ -56,7 +56,8 @@
api
vocabulary-spi
- core
+ core
+ vocabulary
diff --git a/vocabulary/format-assertion/pom.xml b/vocabulary/format-assertion/pom.xml
new file mode 100644
index 0000000..2b2b387
--- /dev/null
+++ b/vocabulary/format-assertion/pom.xml
@@ -0,0 +1,78 @@
+
+
+ 4.0.0
+
+
+ io.github.sebastian-toepfer.json-schema.vocabulary
+ json-schema-vocabulary
+ 0.4.0-SNAPSHOT
+
+
+ json-schema-vocabulary-format-assertion
+ Json Schema :: vocabulary :: format-assertion
+
+
+
+ io.github.sebastian-toepfer.json-schema
+ json-schema-vocabulary-spi
+ ${project.version}
+
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-params
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+ org.hamcrest
+ hamcrest
+ test
+
+
+ com.github.npathai
+ hamcrest-optional
+ test
+
+
+ io.github.sebastian-toepfer.ddd
+ media-core
+ test
+
+
+
+ jakarta.json
+ jakarta.json-api
+ provided
+
+
+ com.github.spotbugs
+ spotbugs-annotations
+ true
+ provided
+
+
+
+ org.eclipse.parsson
+ parsson
+ test
+
+
+ io.github.sebastian-toepfer.json-schema
+ json-schema-core
+ ${project.version}
+ test
+
+
+
diff --git a/vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatAssertionKeyWordType.java b/vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatAssertionKeyWordType.java
new file mode 100644
index 0000000..5a79c5a
--- /dev/null
+++ b/vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatAssertionKeyWordType.java
@@ -0,0 +1,49 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.vocabulary.formatassertion;
+
+import static io.github.sebastiantoepfer.jsonschema.vocabulary.formatassertion.FormatKeyword.NAME;
+
+import io.github.sebastiantoepfer.jsonschema.JsonSchema;
+import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
+import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType;
+
+final class FormatAssertionKeyWordType implements KeywordType {
+
+ private final Formats formats;
+
+ public FormatAssertionKeyWordType(final Formats formats) {
+ this.formats = formats;
+ }
+
+ @Override
+ public String name() {
+ return NAME;
+ }
+
+ @Override
+ public Keyword createKeyword(final JsonSchema schema) {
+ return new FormatKeyword(formats.findByName(schema.asJsonObject().getString(NAME)));
+ }
+}
diff --git a/vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatAssertionVocabulary.java b/vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatAssertionVocabulary.java
new file mode 100644
index 0000000..ac66e47
--- /dev/null
+++ b/vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatAssertionVocabulary.java
@@ -0,0 +1,69 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.vocabulary.formatassertion;
+
+import static io.github.sebastiantoepfer.jsonschema.vocabulary.formatassertion.FormatKeyword.NAME;
+
+import io.github.sebastiantoepfer.jsonschema.Vocabulary;
+import io.github.sebastiantoepfer.jsonschema.keyword.KeywordType;
+import io.github.sebastiantoepfer.jsonschema.vocabulary.spi.LazyVocabularies;
+import java.net.URI;
+import java.util.Objects;
+import java.util.Optional;
+
+public final class FormatAssertionVocabulary implements LazyVocabularies, Vocabulary {
+
+ private final URI id;
+
+ public FormatAssertionVocabulary() {
+ id = URI.create("https://json-schema.org/draft/2020-12/vocab/format-assertion");
+ }
+
+ @Override
+ public Optional loadVocabularyWithId(final URI id) {
+ final Optional result;
+ if (id().equals(id)) {
+ result = Optional.of(this);
+ } else {
+ result = Optional.empty();
+ }
+ return result;
+ }
+
+ @Override
+ public URI id() {
+ return id;
+ }
+
+ @Override
+ public Optional findKeywordTypeByName(final String name) {
+ final Optional result;
+ if (Objects.equals(NAME, name)) {
+ result = Optional.of(new FormatAssertionKeyWordType(new Formats()));
+ } else {
+ result = Optional.empty();
+ }
+ return result;
+ }
+}
diff --git a/vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatKeyword.java b/vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatKeyword.java
new file mode 100644
index 0000000..2c2a601
--- /dev/null
+++ b/vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatKeyword.java
@@ -0,0 +1,74 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.vocabulary.formatassertion;
+
+import io.github.sebastiantoepfer.ddd.common.Media;
+import io.github.sebastiantoepfer.jsonschema.InstanceType;
+import io.github.sebastiantoepfer.jsonschema.keyword.Annotation;
+import io.github.sebastiantoepfer.jsonschema.keyword.Assertion;
+import jakarta.json.Json;
+import jakarta.json.JsonString;
+import jakarta.json.JsonValue;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+
+final class FormatKeyword implements Assertion, Annotation {
+
+ static final String NAME = "format";
+ private final Formats.Format format;
+
+ FormatKeyword(final Formats.Format format) {
+ this.format = Objects.requireNonNull(format);
+ }
+
+ @Override
+ public Collection categories() {
+ return List.of(KeywordCategory.ASSERTION, KeywordCategory.ANNOTATION);
+ }
+
+ @Override
+ public boolean isValidFor(final JsonValue instance) {
+ return !InstanceType.STRING.isInstance(instance) || hasValidValue((JsonString) instance);
+ }
+
+ private boolean hasValidValue(final JsonString value) {
+ return format.applyTo(value.getString());
+ }
+
+ @Override
+ public boolean hasName(final String name) {
+ return NAME.equals(name);
+ }
+
+ @Override
+ public JsonValue valueFor(final JsonValue value) {
+ return Json.createValue(format.name());
+ }
+
+ @Override
+ public > T printOn(final T media) {
+ return media.withValue(NAME, format.name());
+ }
+}
diff --git a/vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/Formats.java b/vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/Formats.java
new file mode 100644
index 0000000..7cc6542
--- /dev/null
+++ b/vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/Formats.java
@@ -0,0 +1,96 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.vocabulary.formatassertion;
+
+import io.github.sebastiantoepfer.jsonschema.vocabulary.formatassertion.rfc.Rfc;
+import io.github.sebastiantoepfer.jsonschema.vocabulary.formatassertion.rfc.Rfc3339;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+final class Formats {
+
+ private static final List RFCS = Map.ofEntries(
+ Map.entry("date-time", "date-time"),
+ Map.entry("date", "full-date"),
+ Map.entry("time", "full-time"),
+ Map.entry("duration", "duration")
+ )
+ .entrySet()
+ .stream()
+ .map(entry -> new RfcBasedFormat(entry.getKey(), new Rfc3339(), entry.getValue()))
+ .map(Format.class::cast)
+ .toList();
+
+ Format findByName(final String name) {
+ return RFCS.stream().filter(f -> f.name().equals(name)).findFirst().orElseGet(() -> new UnknownFormat(name));
+ }
+
+ private static class RfcBasedFormat implements Format {
+
+ private final String formatName;
+ private final Rfc rfc;
+ private final String ruleName;
+
+ public RfcBasedFormat(final String formatName, final Rfc rfc, final String ruleName) {
+ this.formatName = Objects.requireNonNull(formatName);
+ this.rfc = Objects.requireNonNull(rfc);
+ this.ruleName = Objects.requireNonNull(ruleName);
+ }
+
+ @Override
+ public boolean applyTo(final String value) {
+ return rfc.findRuleByName(ruleName).map(r -> r.applyTo(value)).orElse(Boolean.FALSE);
+ }
+
+ @Override
+ public String name() {
+ return formatName;
+ }
+ }
+
+ interface Format {
+ boolean applyTo(String value);
+ String name();
+ }
+
+ private static class UnknownFormat implements Format {
+
+ private final String name;
+
+ public UnknownFormat(final String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String name() {
+ return name;
+ }
+
+ @Override
+ public boolean applyTo(final String value) {
+ return false;
+ }
+ }
+}
diff --git a/vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/rfc/RegExRule.java b/vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/rfc/RegExRule.java
new file mode 100644
index 0000000..3814d3c
--- /dev/null
+++ b/vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/rfc/RegExRule.java
@@ -0,0 +1,41 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.vocabulary.formatassertion.rfc;
+
+import java.util.Objects;
+import java.util.regex.Pattern;
+
+final class RegExRule implements Rule {
+
+ private final Pattern pattern;
+
+ public RegExRule(final Pattern pattern) {
+ this.pattern = Objects.requireNonNull(pattern);
+ }
+
+ @Override
+ public boolean applyTo(final String value) {
+ return pattern.matcher(value).matches();
+ }
+}
diff --git a/vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/rfc/Rfc.java b/vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/rfc/Rfc.java
new file mode 100644
index 0000000..810dd6e
--- /dev/null
+++ b/vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/rfc/Rfc.java
@@ -0,0 +1,30 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.vocabulary.formatassertion.rfc;
+
+import java.util.Optional;
+
+public interface Rfc {
+ Optional findRuleByName(String ruleName);
+}
diff --git a/vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/rfc/Rfc3339.java b/vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/rfc/Rfc3339.java
new file mode 100644
index 0000000..11a9db6
--- /dev/null
+++ b/vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/rfc/Rfc3339.java
@@ -0,0 +1,59 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.vocabulary.formatassertion.rfc;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.regex.Pattern;
+
+//create regex with: https://abnf.msweet.org/index.php
+public final class Rfc3339 implements Rfc {
+
+ private static final String DATE = "\\d{4}\\-\\d{2}\\-\\d{2}";
+ private static final String TIMEZONE = "([Zz]|([+-]\\d{2}\\:\\d{2}))";
+ private static final String TIME = "\\d{2}\\:\\d{2}\\:\\d{2}(\\.\\d+)?" + TIMEZONE;
+
+ private static final Map RULES = Map.of(
+ "date-time",
+ Pattern.compile("^" + DATE + "[Tt]" + TIME + "$"),
+ "full-date",
+ Pattern.compile("^" + DATE + "$"),
+ "full-time",
+ Pattern.compile("^" + TIME + "$"),
+ "duration",
+ Pattern.compile(
+ "^" +
+ "([Pp]((" +
+ "(\\d+[Dd]|\\d+[Mm](\\d+[Dd])?|\\d+[Yy](\\d+[Mm](\\d+[Dd])?)?)" +
+ "(([Tt](\\d+[Hh](\\d+[Mm](\\d+[Ss])?)?|\\d+[Mm](\\d+[Ss])?|\\d+[Ss])))?" +
+ ")|([Tt](\\d+[Hh](\\d+[Mm](\\d+[Ss])?)?|\\d+[Mm](\\d+[Ss])?|\\d+[Ss]))|\\d+[Ww]))" +
+ "$"
+ )
+ );
+
+ @Override
+ public Optional findRuleByName(final String ruleName) {
+ return Optional.ofNullable(RULES.get(ruleName)).map(RegExRule::new);
+ }
+}
diff --git a/vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/rfc/Rule.java b/vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/rfc/Rule.java
new file mode 100644
index 0000000..2e4c1aa
--- /dev/null
+++ b/vocabulary/format-assertion/src/main/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/rfc/Rule.java
@@ -0,0 +1,28 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.vocabulary.formatassertion.rfc;
+
+public interface Rule {
+ boolean applyTo(String value);
+}
diff --git a/vocabulary/format-assertion/src/main/java/module-info.java b/vocabulary/format-assertion/src/main/java/module-info.java
new file mode 100644
index 0000000..fd4d7c0
--- /dev/null
+++ b/vocabulary/format-assertion/src/main/java/module-info.java
@@ -0,0 +1,33 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+module io.github.sebastiantoepfer.jsonschema.vocabulary.formatassertion {
+ requires io.github.sebastiantoepfer.jsonschema;
+ requires io.github.sebastiantoepfer.jsonschema.vocabulary.spi;
+ requires io.github.sebastiantoepfer.ddd.common;
+ requires com.github.spotbugs.annotations;
+ requires jakarta.json;
+
+ provides io.github.sebastiantoepfer.jsonschema.vocabulary.spi.LazyVocabularies
+ with io.github.sebastiantoepfer.jsonschema.vocabulary.formatassertion.FormatAssertionVocabulary;
+}
diff --git a/vocabulary/format-assertion/src/main/resources/rfc/rfc3339 b/vocabulary/format-assertion/src/main/resources/rfc/rfc3339
new file mode 100644
index 0000000..446b791
--- /dev/null
+++ b/vocabulary/format-assertion/src/main/resources/rfc/rfc3339
@@ -0,0 +1,30 @@
+date-fullyear = 4DIGIT
+date-month = 2DIGIT ; 01-12
+date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on
+ ; month/year
+time-hour = 2DIGIT ; 00-23
+time-minute = 2DIGIT ; 00-59
+time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on leap second
+ ; rules
+time-secfrac = "." 1*DIGIT
+time-numoffset = ("+" / "-") time-hour ":" time-minute
+time-offset = "Z" / time-numoffset
+
+partial-time = time-hour ":" time-minute ":" time-second
+ [time-secfrac]
+full-date = date-fullyear "-" date-month "-" date-mday
+full-time = partial-time time-offset
+
+date-time = full-date "T" full-time
+
+dur-second = 1*DIGIT "S"
+dur-minute = 1*DIGIT "M" [dur-second]
+dur-hour = 1*DIGIT "H" [dur-minute]
+dur-time = "T" (dur-hour / dur-minute / dur-second)
+dur-day = 1*DIGIT "D"
+dur-week = 1*DIGIT "W"
+dur-month = 1*DIGIT "M" [dur-day]
+dur-year = 1*DIGIT "Y" [dur-month]
+dur-date = (dur-day / dur-month / dur-year) [dur-time]
+
+duration = "P" (dur-date / dur-time / dur-week)
\ No newline at end of file
diff --git a/vocabulary/format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatAssertionKeyWordTypeTest.java b/vocabulary/format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatAssertionKeyWordTypeTest.java
new file mode 100644
index 0000000..950be2e
--- /dev/null
+++ b/vocabulary/format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatAssertionKeyWordTypeTest.java
@@ -0,0 +1,50 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.vocabulary.formatassertion;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import io.github.sebastiantoepfer.jsonschema.JsonSchemas;
+import jakarta.json.Json;
+import org.junit.jupiter.api.Test;
+
+class FormatAssertionKeyWordTypeTest {
+
+ @Test
+ void should_create_formatassertionkeyword() {
+ assertThat(
+ new FormatAssertionKeyWordType(new Formats()).createKeyword(
+ JsonSchemas.load(Json.createObjectBuilder().add("format", "email").build())
+ ),
+ is(instanceOf(FormatKeyword.class))
+ );
+ }
+
+ @Test
+ void should_know_her_name() {
+ assertThat(new FormatAssertionKeyWordType(new Formats()).name(), is("format"));
+ }
+}
diff --git a/vocabulary/format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatAssertionVocabularyTest.java b/vocabulary/format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatAssertionVocabularyTest.java
new file mode 100644
index 0000000..baba2a0
--- /dev/null
+++ b/vocabulary/format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatAssertionVocabularyTest.java
@@ -0,0 +1,64 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.vocabulary.formatassertion;
+
+import static com.github.npathai.hamcrestopt.OptionalMatchers.isEmpty;
+import static com.github.npathai.hamcrestopt.OptionalMatchers.isPresent;
+import static com.github.npathai.hamcrestopt.OptionalMatchers.isPresentAnd;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import java.net.URI;
+import org.junit.jupiter.api.Test;
+
+class FormatAssertionVocabularyTest {
+
+ @Test
+ void should_return_empty_optional_for_unknow_id() {
+ assertThat(new FormatAssertionVocabulary().loadVocabularyWithId(URI.create("hello")), isEmpty());
+ }
+
+ @Test
+ void should_return_non_empty_optional_for_right_id() {
+ assertThat(
+ new FormatAssertionVocabulary()
+ .loadVocabularyWithId(URI.create("https://json-schema.org/draft/2020-12/vocab/format-assertion")),
+ isPresent()
+ );
+ }
+
+ @Test
+ void should_return_empty_for_invalid_keywordname() {
+ assertThat(new FormatAssertionVocabulary().findKeywordTypeByName("$schema"), isEmpty());
+ }
+
+ @Test
+ void should_return_keywordtype_for_format_keyword() {
+ assertThat(
+ new FormatAssertionVocabulary().findKeywordTypeByName("format"),
+ isPresentAnd(is(instanceOf(FormatAssertionKeyWordType.class)))
+ );
+ }
+}
diff --git a/vocabulary/format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatKeywordTest.java b/vocabulary/format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatKeywordTest.java
new file mode 100644
index 0000000..cb4f1d2
--- /dev/null
+++ b/vocabulary/format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatKeywordTest.java
@@ -0,0 +1,89 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.vocabulary.formatassertion;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.hasEntry;
+
+import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia;
+import io.github.sebastiantoepfer.jsonschema.keyword.Keyword;
+import jakarta.json.Json;
+import org.junit.jupiter.api.Test;
+
+class FormatKeywordTest {
+
+ @Test
+ void should_be_valid_for_any_number() {
+ assertThat(new FormatKeyword(new Formats().findByName("unknow")).isValidFor(Json.createValue(42)), is(true));
+ }
+
+ @Test
+ void should_be_invalid_for_any_string_with_unknow_format() {
+ assertThat(new FormatKeyword(new Formats().findByName("unknow")).isValidFor(Json.createValue("42")), is(false));
+ }
+
+ @Test
+ void should_be_valid_for_valid_formated_string() {
+ assertThat(
+ new FormatKeyword(new Formats().findByName("date-time"))
+ .asAssertion()
+ .isValidFor(Json.createValue("2024-11-29T00:05:00+01:00")),
+ is(true)
+ );
+ }
+
+ @Test
+ void should_know_hisName() {
+ final FormatKeyword keyword = new FormatKeyword(new Formats().findByName("unknow"));
+
+ assertThat(keyword.hasName("test"), is(false));
+ assertThat(keyword.hasName("format"), is(true));
+ }
+
+ @Test
+ void should_by_an_annotation_and_assertion() {
+ assertThat(
+ new FormatKeyword(new Formats().findByName("unknow")).categories(),
+ containsInAnyOrder(Keyword.KeywordCategory.ANNOTATION, Keyword.KeywordCategory.ASSERTION)
+ );
+ }
+
+ @Test
+ void should_retrun_name_of_format() {
+ assertThat(
+ new FormatKeyword(new Formats().findByName("date-time")).asAnnotation().valueFor(Json.createValue("")),
+ is(Json.createValue("date-time"))
+ );
+ }
+
+ @Test
+ void should_be_printable() {
+ assertThat(
+ new FormatKeyword(new Formats().findByName("unknow")).printOn(new HashMapMedia()),
+ hasEntry(is("format"), is("unknow"))
+ );
+ }
+}
diff --git a/vocabulary/format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatsTest.java b/vocabulary/format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatsTest.java
new file mode 100644
index 0000000..4dec5bd
--- /dev/null
+++ b/vocabulary/format-assertion/src/test/java/io/github/sebastiantoepfer/jsonschema/vocabulary/formatassertion/FormatsTest.java
@@ -0,0 +1,62 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package io.github.sebastiantoepfer.jsonschema.vocabulary.formatassertion;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import org.junit.jupiter.api.Test;
+
+class FormatsTest {
+
+ @Test
+ void should_return_unknown() {
+ assertThat(new Formats().findByName("unknow").name(), is("unknow"));
+ assertThat(new Formats().findByName("unknow").applyTo("value"), is(false));
+ }
+
+ @Test
+ void should_found_dateTimeFormat() {
+ assertThat(new Formats().findByName("date-time").applyTo("2024-11-29T00:05:00+01:00"), is(true));
+ assertThat(new Formats().findByName("date-time").applyTo("noDateTime"), is(false));
+ }
+
+ @Test
+ void should_found_dateFormat() {
+ assertThat(new Formats().findByName("date").applyTo("2024-11-29"), is(true));
+ assertThat(new Formats().findByName("date").applyTo("noDate"), is(false));
+ }
+
+ @Test
+ void should_found_timeFormat() {
+ assertThat(new Formats().findByName("time").applyTo("00:05:00.0182Z"), is(true));
+ assertThat(new Formats().findByName("time").applyTo("noTime"), is(false));
+ }
+
+ @Test
+ void should_found_durationFormat() {
+ assertThat(new Formats().findByName("duration").applyTo("PT1H10M"), is(true));
+ assertThat(new Formats().findByName("duration").applyTo("noDuration"), is(false));
+ }
+}
diff --git a/vocabulary/format-assertion/src/test/java/module-info.java b/vocabulary/format-assertion/src/test/java/module-info.java
new file mode 100644
index 0000000..e4e0dc4
--- /dev/null
+++ b/vocabulary/format-assertion/src/test/java/module-info.java
@@ -0,0 +1,38 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2024 sebastian.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+open module io.github.sebastiantoepfer.jsonschema.vocabulary.formatassertion {
+ requires io.github.sebastiantoepfer.jsonschema;
+ requires io.github.sebastiantoepfer.jsonschema.vocabulary.spi;
+ requires io.github.sebastiantoepfer.ddd.common;
+ requires jakarta.json;
+
+ requires org.junit.jupiter.api;
+ requires org.junit.jupiter.params;
+ requires org.junit.jupiter.engine;
+ requires org.hamcrest;
+ requires hamcrest.optional;
+
+ requires io.github.sebastiantoepfer.ddd.media.core;
+}
diff --git a/vocabulary/pom.xml b/vocabulary/pom.xml
new file mode 100644
index 0000000..e888e99
--- /dev/null
+++ b/vocabulary/pom.xml
@@ -0,0 +1,22 @@
+
+
+
+ 4.0.0
+
+
+ io.github.sebastian-toepfer.json-schema
+ json-schema
+ 0.4.0-SNAPSHOT
+
+
+ io.github.sebastian-toepfer.json-schema.vocabulary
+ json-schema-vocabulary
+ Json Schema :: vocabulary
+ pom
+
+
+ format-assertion
+
+