diff --git a/src/main/java/io/vertx/json/schema/Draft.java b/src/main/java/io/vertx/json/schema/Draft.java
index e766c42b..82ffadba 100644
--- a/src/main/java/io/vertx/json/schema/Draft.java
+++ b/src/main/java/io/vertx/json/schema/Draft.java
@@ -25,30 +25,43 @@ public enum Draft {
/**
* Draft 4 - http://json-schema.org/draft-04/schema#
*
- * Usually used by Swagger 2.0
+ * Usually used by OpenAPI 3.0
*/
- DRAFT4,
+ DRAFT4("http://json-schema.org/draft-04/schema#"),
/**
* Draft 7 - http://json-schema.org/draft-07/schema#
*
- * Usually used by OpenAPI 3.0
+ * Commonly used by many projects
*/
- DRAFT7,
+ DRAFT7("http://json-schema.org/draft-07/schema#"),
/**
* Draft 2019-09 - https://json-schema.org/draft/2019-09/schema
*
* Commonly used by many projects
*/
- DRAFT201909,
+ DRAFT201909("https://json-schema.org/draft/2019-09/schema"),
/**
- * Draft 2019-09 - https://json-schema.org/draft/2020-12/schema
+ * Draft 2020-12 - https://json-schema.org/draft/2020-12/schema
*
* Usually used by OpenAPI 3.1
*/
- DRAFT202012;
+ DRAFT202012("https://json-schema.org/draft/2020-12/schema");
+
+ private final String identifier;
+
+ Draft(String identifier) {
+ this.identifier = identifier;
+ }
+
+ /**
+ * @return the identifier of the draft version.
+ */
+ public String getIdentifier() {
+ return identifier;
+ }
/**
* Converts a draft number to a {@link Draft} enum value.
@@ -75,7 +88,7 @@ public static Draft from(String string) {
}
/**
- * Converts a draft idenfifier to a {@link Draft} enum value.
+ * Converts a draft identifier to a {@link Draft} enum value.
* @param string The identifier (in URL format)
* @return a Draft enum value
*/
@@ -83,17 +96,16 @@ public static Draft fromIdentifier(String string) {
if (string == null) {
throw new IllegalArgumentException("Invalid draft identifier: null");
}
- switch (string) {
- case "http://json-schema.org/draft-04/schema#":
- return DRAFT4;
- case "http://json-schema.org/draft-07/schema#":
- return DRAFT7;
- case "https://json-schema.org/draft/2019-09/schema":
- return DRAFT201909;
- case "https://json-schema.org/draft/2020-12/schema":
- return DRAFT202012;
- default:
- throw new IllegalArgumentException("Unsupported draft identifier: " + string);
+ if(DRAFT4.identifier.equals(string)) {
+ return DRAFT4;
+ } else if(DRAFT7.identifier.equals(string)) {
+ return DRAFT7;
+ } else if(DRAFT201909.identifier.equals(string)) {
+ return DRAFT201909;
+ } else if(DRAFT202012.identifier.equals(string)) {
+ return DRAFT202012;
+ } else {
+ throw new IllegalArgumentException("Unsupported draft identifier: " + string);
}
}
}
diff --git a/src/main/java/io/vertx/json/schema/SchemaRepository.java b/src/main/java/io/vertx/json/schema/SchemaRepository.java
index 34582232..f11574cc 100644
--- a/src/main/java/io/vertx/json/schema/SchemaRepository.java
+++ b/src/main/java/io/vertx/json/schema/SchemaRepository.java
@@ -12,12 +12,13 @@
import io.vertx.codegen.annotations.Fluent;
import io.vertx.codegen.annotations.VertxGen;
+import io.vertx.core.file.FileSystem;
import io.vertx.core.json.JsonObject;
import io.vertx.json.schema.impl.SchemaRepositoryImpl;
/**
* A repository is a holder of dereferenced schemas, it can be used to create validator instances for a specific schema.
- *
+ *
* This is to be used when multiple schema objects compose the global schema to be used for validation.
*
* @author Paulo Lopes
@@ -27,6 +28,7 @@ public interface SchemaRepository {
/**
* Create a repository with some initial configuration.
+ *
* @param options the initial configuration
* @return a repository
*/
@@ -38,8 +40,8 @@ static SchemaRepository create(JsonSchemaOptions options) {
* Dereferences a schema to the repository.
*
* @param schema a new schema to list
- * @throws SchemaException when a schema is already present for the same id
* @return a repository
+ * @throws SchemaException when a schema is already present for the same id
*/
@Fluent
SchemaRepository dereference(JsonSchema schema) throws SchemaException;
@@ -47,15 +49,36 @@ static SchemaRepository create(JsonSchemaOptions options) {
/**
* Dereferences a schema to the repository.
*
- * @param uri the source of the schema used for de-referencing, optionally relative to
- * {@link JsonSchemaOptions#getBaseUri()}.
+ * @param uri the source of the schema used for de-referencing, optionally relative to
+ * {@link JsonSchemaOptions#getBaseUri()}.
* @param schema a new schema to list
- * @throws SchemaException when a schema is already present for the same id
* @return a repository
+ * @throws SchemaException when a schema is already present for the same id
*/
@Fluent
SchemaRepository dereference(String uri, JsonSchema schema) throws SchemaException;
+ /**
+ * Preloads the repository with the meta schemas for the related @link {@link Draft} version. The related draft version
+ * is determined from the {@link JsonSchemaOptions}, in case that no draft is set in the options an
+ * {@link IllegalStateException} is thrown.
+ *
+ * @param fs The Vert.x file system to load the related schema meta files from classpath
+ * @return a repository
+ */
+ @Fluent
+ SchemaRepository preloadMetaSchema(FileSystem fs);
+
+ /**
+ * Preloads the repository with the meta schemas for the related draft version.
+ *
+ * @param fs The Vert.x file system to load the related schema meta files from classpath
+ * @param draft The draft version of the meta files to load
+ * @return a repository
+ */
+ @Fluent
+ SchemaRepository preloadMetaSchema(FileSystem fs, Draft draft);
+
/**
* A new validator instance using this repository options.
*
@@ -75,7 +98,7 @@ static SchemaRepository create(JsonSchemaOptions options) {
/**
* A new validator instance overriding this repository options.
*
- * @param schema the start validation schema
+ * @param schema the start validation schema
* @param options the options to be using on the validator instance
* @return the validator
*/
@@ -84,7 +107,7 @@ static SchemaRepository create(JsonSchemaOptions options) {
/**
* A new validator instance overriding this repository options.
*
- * @param ref the start validation reference in JSON pointer format
+ * @param ref the start validation reference in JSON pointer format
* @param options the options to be using on the validator instance
* @return the validator
*/
@@ -92,7 +115,7 @@ static SchemaRepository create(JsonSchemaOptions options) {
/**
* Tries to resolve all internal and repository local references. External references are not resolved.
- *
+ *
* The result is an object where all references have been resolved. Resolution of references is shallow. This
* should normally not be a problem for this use case.
*
@@ -103,7 +126,7 @@ static SchemaRepository create(JsonSchemaOptions options) {
/**
* Tries to resolve all internal and repository local references. External references are not resolved.
- *
+ *
* The result is an object where all references have been resolved. Resolution of references is shallow. This
* should normally not be a problem for this use case.
*
@@ -115,6 +138,7 @@ static SchemaRepository create(JsonSchemaOptions options) {
/**
* Look up a schema using a JSON pointer notation
+ *
* @param pointer the JSON pointer
* @return the schema
*/
diff --git a/src/main/java/io/vertx/json/schema/impl/SchemaRepositoryImpl.java b/src/main/java/io/vertx/json/schema/impl/SchemaRepositoryImpl.java
index 7b1d4586..c2f157aa 100644
--- a/src/main/java/io/vertx/json/schema/impl/SchemaRepositoryImpl.java
+++ b/src/main/java/io/vertx/json/schema/impl/SchemaRepositoryImpl.java
@@ -1,5 +1,6 @@
package io.vertx.json.schema.impl;
+import io.vertx.core.file.FileSystem;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.json.schema.*;
@@ -64,6 +65,35 @@ public class SchemaRepositoryImpl implements SchemaRepository {
"else"
);
+ static final List DRAFT_4_META_FILES = Arrays.asList(
+ "http://json-schema.org/draft-04/schema"
+ );
+
+ static final List DRAFT_7_META_FILES = Arrays.asList(
+ "http://json-schema.org/draft-07/schema"
+ );
+
+ static final List DRAFT_201909_META_FILES = Arrays.asList(
+ "https://json-schema.org/draft/2019-09/schema",
+ "https://json-schema.org/draft/2019-09/meta/core",
+ "https://json-schema.org/draft/2019-09/meta/applicator",
+ "https://json-schema.org/draft/2019-09/meta/validation",
+ "https://json-schema.org/draft/2019-09/meta/meta-data",
+ "https://json-schema.org/draft/2019-09/meta/format",
+ "https://json-schema.org/draft/2019-09/meta/content"
+ );
+
+ static final List DRAFT_202012_META_FILES = Arrays.asList(
+ "https://json-schema.org/draft/2020-12/schema",
+ "https://json-schema.org/draft/2020-12/meta/core",
+ "https://json-schema.org/draft/2020-12/meta/applicator",
+ "https://json-schema.org/draft/2020-12/meta/validation",
+ "https://json-schema.org/draft/2020-12/meta/meta-data",
+ "https://json-schema.org/draft/2020-12/meta/format-annotation",
+ "https://json-schema.org/draft/2020-12/meta/content",
+ "https://json-schema.org/draft/2020-12/meta/unevaluated"
+ );
+
private final Map lookup = new HashMap<>();
private final JsonSchemaOptions options;
@@ -88,6 +118,43 @@ public SchemaRepository dereference(String uri, JsonSchema schema) throws Schema
return this;
}
+ @Override
+ public SchemaRepository preloadMetaSchema(FileSystem fs) {
+ if (options.getDraft() == null) {
+ throw new IllegalStateException("No draft version is defined in the options of the repository");
+ }
+ return preloadMetaSchema(fs, options.getDraft());
+ }
+
+ @Override
+ public SchemaRepository preloadMetaSchema(FileSystem fs, Draft draft) {
+ List metaSchemaIds;
+ switch (draft) {
+ case DRAFT4:
+ metaSchemaIds = DRAFT_4_META_FILES;
+ break;
+ case DRAFT7:
+ metaSchemaIds = DRAFT_7_META_FILES;
+ break;
+ case DRAFT201909:
+ metaSchemaIds = DRAFT_201909_META_FILES;
+ break;
+ case DRAFT202012:
+ metaSchemaIds = DRAFT_202012_META_FILES;
+ break;
+ default:
+ throw new IllegalStateException();
+ }
+
+ for (String id : metaSchemaIds) {
+ // read files from classpath
+ JsonSchema schema = JsonSchema.of(fs.readFileBlocking(id.substring(id.indexOf("://") + 3)).toJsonObject());
+ // try to extract the '$id' from the schema itself, fallback to old field 'id' and if not present to the given url
+ dereference(schema.get("$id", schema.get("id", id)), schema);
+ }
+ return this;
+ }
+
@Override
public Validator validator(JsonSchema schema) {
return new SchemaValidatorImpl(schema, options, Collections.unmodifiableMap(lookup));
@@ -97,6 +164,9 @@ public Validator validator(JsonSchema schema) {
public Validator validator(String ref) {
// resolve the pointer to an absolute path
final URL url = new URL(ref, baseUri);
+ if ("".equals(url.fragment())) {
+ url.anchor(""); // normalize hash https://url.spec.whatwg.org/#dom-url-hash
+ }
final String uri = url.href();
if (lookup.containsKey(uri)) {
return new SchemaValidatorImpl(uri, options, Collections.unmodifiableMap(lookup));
@@ -131,6 +201,9 @@ public Validator validator(String ref, JsonSchemaOptions options) {
// resolve the pointer to an absolute path
final URL url = new URL(ref, baseUri);
final String uri = url.href();
+ if ("".equals(url.fragment())) {
+ url.anchor(""); // normalize hash https://url.spec.whatwg.org/#dom-url-hash
+ }
if (lookup.containsKey(uri)) {
return new SchemaValidatorImpl(uri, config, Collections.unmodifiableMap(lookup));
}
@@ -151,6 +224,9 @@ public JsonObject resolve(JsonSchema schema) {
public JsonObject resolve(String ref) {
// resolve the pointer to an absolute path
final URL url = new URL(ref, baseUri);
+ if ("".equals(url.fragment())) {
+ url.anchor(""); // normalize hash https://url.spec.whatwg.org/#dom-url-hash
+ }
final String uri = url.href();
if (lookup.containsKey(uri)) {
return Ref.resolve(Collections.unmodifiableMap(lookup), baseUri, lookup.get(uri));
diff --git a/src/test/java/io/vertx/json/schema/SchemaDefinitionValidationTest.java b/src/test/java/io/vertx/json/schema/SchemaDefinitionValidationTest.java
new file mode 100644
index 00000000..1ea5913e
--- /dev/null
+++ b/src/test/java/io/vertx/json/schema/SchemaDefinitionValidationTest.java
@@ -0,0 +1,50 @@
+package io.vertx.json.schema;
+
+import io.vertx.core.Vertx;
+import io.vertx.core.buffer.Buffer;
+import io.vertx.junit5.VertxExtension;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.stream.Stream;
+
+import static io.vertx.json.schema.Draft.DRAFT201909;
+import static io.vertx.json.schema.Draft.DRAFT202012;
+import static io.vertx.json.schema.Draft.DRAFT4;
+import static io.vertx.json.schema.Draft.DRAFT7;
+
+@ExtendWith(VertxExtension.class)
+class SchemaDefinitionValidationTest {
+
+ private static final Path RESOURCE_PATH = Paths.get("src", "test", "resources", "schema_definition_validation");
+
+ private static Stream testSchemaDefinitionValidation() {
+ return Stream.of(
+ Arguments.of(DRAFT4, RESOURCE_PATH.resolve("OpenAPI3_0.json")),
+ Arguments.of(DRAFT7, RESOURCE_PATH.resolve("angular_cli_workspace_schema.json")),
+ Arguments.of(DRAFT201909, RESOURCE_PATH.resolve("compose_spec.json")),
+ Arguments.of(DRAFT202012, RESOURCE_PATH.resolve("OpenAPI3_1.json"))
+ );
+ }
+
+ @ParameterizedTest(name = "{index} test preloadMetaSchema with draft {0}")
+ @MethodSource
+ void testSchemaDefinitionValidation(Draft draft, Path schemaPath, Vertx vertx) throws IOException {
+ JsonSchemaOptions opts = new JsonSchemaOptions().setBaseUri("https://example.org");
+ SchemaRepository repo = SchemaRepository.create(opts);
+ repo.preloadMetaSchema(vertx.fileSystem(), draft);
+
+ Buffer schemaBuffer = Buffer.buffer(Files.readAllBytes(schemaPath));
+ JsonSchema schemaToValidate = JsonSchema.of(schemaBuffer.toJsonObject());
+
+ OutputUnit res = repo.validator(draft.getIdentifier()).validate(schemaToValidate);
+ Assertions.assertTrue(res.getValid());
+ }
+}
diff --git a/src/test/java/io/vertx/json/schema/impl/SchemaRepositoryImplTest.java b/src/test/java/io/vertx/json/schema/impl/SchemaRepositoryImplTest.java
new file mode 100644
index 00000000..14835b74
--- /dev/null
+++ b/src/test/java/io/vertx/json/schema/impl/SchemaRepositoryImplTest.java
@@ -0,0 +1,78 @@
+package io.vertx.json.schema.impl;
+
+import io.vertx.core.Vertx;
+import io.vertx.core.file.FileSystem;
+import io.vertx.json.schema.Draft;
+import io.vertx.json.schema.JsonSchemaOptions;
+import io.vertx.json.schema.SchemaRepository;
+import io.vertx.junit5.VertxExtension;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.List;
+import java.util.stream.Stream;
+
+import static io.vertx.json.schema.Draft.DRAFT201909;
+import static io.vertx.json.schema.Draft.DRAFT202012;
+import static io.vertx.json.schema.Draft.DRAFT4;
+import static io.vertx.json.schema.Draft.DRAFT7;
+import static io.vertx.json.schema.impl.SchemaRepositoryImpl.DRAFT_201909_META_FILES;
+import static io.vertx.json.schema.impl.SchemaRepositoryImpl.DRAFT_202012_META_FILES;
+import static io.vertx.json.schema.impl.SchemaRepositoryImpl.DRAFT_4_META_FILES;
+import static io.vertx.json.schema.impl.SchemaRepositoryImpl.DRAFT_7_META_FILES;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.endsWith;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+@ExtendWith(VertxExtension.class)
+class SchemaRepositoryImplTest {
+
+ private static Stream testPreloadMetaSchema() {
+ return Stream.of(
+ Arguments.of(DRAFT4, DRAFT_4_META_FILES),
+ Arguments.of(DRAFT7, DRAFT_7_META_FILES),
+ Arguments.of(DRAFT201909, DRAFT_201909_META_FILES),
+ Arguments.of(DRAFT202012, DRAFT_202012_META_FILES)
+ );
+ }
+
+ @ParameterizedTest(name = "{index} test preloadMetaSchema with draft {0}")
+ @MethodSource
+ void testPreloadMetaSchema(Draft draft, List ids, Vertx vertx) {
+ JsonSchemaOptions opts = new JsonSchemaOptions().setBaseUri("https://example.org");
+ SchemaRepository repo = SchemaRepository.create(opts);
+ FileSystem fileSystemSpy = spy(vertx.fileSystem());
+ repo.preloadMetaSchema(fileSystemSpy, draft);
+
+ for(String id : ids) {
+ String classpath = id.replace("http://", "").replace("https://", "");
+ verify(fileSystemSpy).readFileBlocking(endsWith(classpath));
+ }
+ }
+
+ @Test
+ @DisplayName("preloadMetaSchema(fs) should throw an error if no draft is set in the options")
+ void testPreloadMetaSchemaException(Vertx vertx) {
+ JsonSchemaOptions opts = new JsonSchemaOptions().setBaseUri("https://example.org");
+ SchemaRepository repo = SchemaRepository.create(opts);
+
+ Assertions.assertThrows(IllegalStateException.class, () -> repo.preloadMetaSchema(vertx.fileSystem()));
+ }
+
+ @Test
+ @DisplayName("preloadMetaSchema(fs) should get the draft from the options")
+ void testPreloadMetaSchemaDraftFromOptions(Vertx vertx) {
+ JsonSchemaOptions opts = new JsonSchemaOptions().setBaseUri("https://example.org").setDraft(DRAFT4);
+ SchemaRepository repoSpy = spy(SchemaRepository.create(opts));
+ repoSpy.preloadMetaSchema(vertx.fileSystem());
+
+ verify(repoSpy).preloadMetaSchema(any(), eq(DRAFT4));
+ }
+}
diff --git a/src/test/resources/schema_definition_validation/OpenAPI3_0.json b/src/test/resources/schema_definition_validation/OpenAPI3_0.json
new file mode 100644
index 00000000..4360553f
--- /dev/null
+++ b/src/test/resources/schema_definition_validation/OpenAPI3_0.json
@@ -0,0 +1,1662 @@
+{
+ "id": "https://spec.openapis.org/oas/3.0/schema/2021-09-28",
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "description": "The description of OpenAPI v3.0.x documents, as defined by https://spec.openapis.org/oas/v3.0.3",
+ "type": "object",
+ "required": [
+ "openapi",
+ "info",
+ "paths"
+ ],
+ "properties": {
+ "openapi": {
+ "type": "string",
+ "pattern": "^3\\.0\\.\\d(-.+)?$"
+ },
+ "info": {
+ "$ref": "#/definitions/Info"
+ },
+ "externalDocs": {
+ "$ref": "#/definitions/ExternalDocumentation"
+ },
+ "servers": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Server"
+ }
+ },
+ "security": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/SecurityRequirement"
+ }
+ },
+ "tags": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Tag"
+ },
+ "uniqueItems": true
+ },
+ "paths": {
+ "$ref": "#/definitions/Paths"
+ },
+ "components": {
+ "$ref": "#/definitions/Components"
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false,
+ "definitions": {
+ "Reference": {
+ "type": "object",
+ "required": [
+ "$ref"
+ ],
+ "patternProperties": {
+ "^\\$ref$": {
+ "type": "string",
+ "format": "uri-reference"
+ }
+ }
+ },
+ "Info": {
+ "type": "object",
+ "required": [
+ "title",
+ "version"
+ ],
+ "properties": {
+ "title": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "termsOfService": {
+ "type": "string",
+ "format": "uri-reference"
+ },
+ "contact": {
+ "$ref": "#/definitions/Contact"
+ },
+ "license": {
+ "$ref": "#/definitions/License"
+ },
+ "version": {
+ "type": "string"
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false
+ },
+ "Contact": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "url": {
+ "type": "string",
+ "format": "uri-reference"
+ },
+ "email": {
+ "type": "string",
+ "format": "email"
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false
+ },
+ "License": {
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "url": {
+ "type": "string",
+ "format": "uri-reference"
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false
+ },
+ "Server": {
+ "type": "object",
+ "required": [
+ "url"
+ ],
+ "properties": {
+ "url": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "variables": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/definitions/ServerVariable"
+ }
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false
+ },
+ "ServerVariable": {
+ "type": "object",
+ "required": [
+ "default"
+ ],
+ "properties": {
+ "enum": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "default": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false
+ },
+ "Components": {
+ "type": "object",
+ "properties": {
+ "schemas": {
+ "type": "object",
+ "patternProperties": {
+ "^[a-zA-Z0-9\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Schema"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ }
+ }
+ },
+ "responses": {
+ "type": "object",
+ "patternProperties": {
+ "^[a-zA-Z0-9\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Reference"
+ },
+ {
+ "$ref": "#/definitions/Response"
+ }
+ ]
+ }
+ }
+ },
+ "parameters": {
+ "type": "object",
+ "patternProperties": {
+ "^[a-zA-Z0-9\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Reference"
+ },
+ {
+ "$ref": "#/definitions/Parameter"
+ }
+ ]
+ }
+ }
+ },
+ "examples": {
+ "type": "object",
+ "patternProperties": {
+ "^[a-zA-Z0-9\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Reference"
+ },
+ {
+ "$ref": "#/definitions/Example"
+ }
+ ]
+ }
+ }
+ },
+ "requestBodies": {
+ "type": "object",
+ "patternProperties": {
+ "^[a-zA-Z0-9\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Reference"
+ },
+ {
+ "$ref": "#/definitions/RequestBody"
+ }
+ ]
+ }
+ }
+ },
+ "headers": {
+ "type": "object",
+ "patternProperties": {
+ "^[a-zA-Z0-9\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Reference"
+ },
+ {
+ "$ref": "#/definitions/Header"
+ }
+ ]
+ }
+ }
+ },
+ "securitySchemes": {
+ "type": "object",
+ "patternProperties": {
+ "^[a-zA-Z0-9\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Reference"
+ },
+ {
+ "$ref": "#/definitions/SecurityScheme"
+ }
+ ]
+ }
+ }
+ },
+ "links": {
+ "type": "object",
+ "patternProperties": {
+ "^[a-zA-Z0-9\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Reference"
+ },
+ {
+ "$ref": "#/definitions/Link"
+ }
+ ]
+ }
+ }
+ },
+ "callbacks": {
+ "type": "object",
+ "patternProperties": {
+ "^[a-zA-Z0-9\\.\\-_]+$": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Reference"
+ },
+ {
+ "$ref": "#/definitions/Callback"
+ }
+ ]
+ }
+ }
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false
+ },
+ "Schema": {
+ "type": "object",
+ "properties": {
+ "title": {
+ "type": "string"
+ },
+ "multipleOf": {
+ "type": "number",
+ "minimum": 0,
+ "exclusiveMinimum": true
+ },
+ "maximum": {
+ "type": "number"
+ },
+ "exclusiveMaximum": {
+ "type": "boolean",
+ "default": false
+ },
+ "minimum": {
+ "type": "number"
+ },
+ "exclusiveMinimum": {
+ "type": "boolean",
+ "default": false
+ },
+ "maxLength": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "minLength": {
+ "type": "integer",
+ "minimum": 0,
+ "default": 0
+ },
+ "pattern": {
+ "type": "string",
+ "format": "regex"
+ },
+ "maxItems": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "minItems": {
+ "type": "integer",
+ "minimum": 0,
+ "default": 0
+ },
+ "uniqueItems": {
+ "type": "boolean",
+ "default": false
+ },
+ "maxProperties": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "minProperties": {
+ "type": "integer",
+ "minimum": 0,
+ "default": 0
+ },
+ "required": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "minItems": 1,
+ "uniqueItems": true
+ },
+ "enum": {
+ "type": "array",
+ "items": {
+ },
+ "minItems": 1,
+ "uniqueItems": false
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "array",
+ "boolean",
+ "integer",
+ "number",
+ "object",
+ "string"
+ ]
+ },
+ "not": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Schema"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ },
+ "allOf": {
+ "type": "array",
+ "items": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Schema"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ }
+ },
+ "oneOf": {
+ "type": "array",
+ "items": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Schema"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ }
+ },
+ "anyOf": {
+ "type": "array",
+ "items": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Schema"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ }
+ },
+ "items": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Schema"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ },
+ "properties": {
+ "type": "object",
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Schema"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ }
+ },
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Schema"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ },
+ {
+ "type": "boolean"
+ }
+ ],
+ "default": true
+ },
+ "description": {
+ "type": "string"
+ },
+ "format": {
+ "type": "string"
+ },
+ "default": {
+ },
+ "nullable": {
+ "type": "boolean",
+ "default": false
+ },
+ "discriminator": {
+ "$ref": "#/definitions/Discriminator"
+ },
+ "readOnly": {
+ "type": "boolean",
+ "default": false
+ },
+ "writeOnly": {
+ "type": "boolean",
+ "default": false
+ },
+ "example": {
+ },
+ "externalDocs": {
+ "$ref": "#/definitions/ExternalDocumentation"
+ },
+ "deprecated": {
+ "type": "boolean",
+ "default": false
+ },
+ "xml": {
+ "$ref": "#/definitions/XML"
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false
+ },
+ "Discriminator": {
+ "type": "object",
+ "required": [
+ "propertyName"
+ ],
+ "properties": {
+ "propertyName": {
+ "type": "string"
+ },
+ "mapping": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "XML": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "namespace": {
+ "type": "string",
+ "format": "uri"
+ },
+ "prefix": {
+ "type": "string"
+ },
+ "attribute": {
+ "type": "boolean",
+ "default": false
+ },
+ "wrapped": {
+ "type": "boolean",
+ "default": false
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false
+ },
+ "Response": {
+ "type": "object",
+ "required": [
+ "description"
+ ],
+ "properties": {
+ "description": {
+ "type": "string"
+ },
+ "headers": {
+ "type": "object",
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Header"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ }
+ },
+ "content": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/definitions/MediaType"
+ }
+ },
+ "links": {
+ "type": "object",
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Link"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ }
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false
+ },
+ "MediaType": {
+ "type": "object",
+ "properties": {
+ "schema": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Schema"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ },
+ "example": {
+ },
+ "examples": {
+ "type": "object",
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Example"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ }
+ },
+ "encoding": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/definitions/Encoding"
+ }
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false,
+ "allOf": [
+ {
+ "$ref": "#/definitions/ExampleXORExamples"
+ }
+ ]
+ },
+ "Example": {
+ "type": "object",
+ "properties": {
+ "summary": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "value": {
+ },
+ "externalValue": {
+ "type": "string",
+ "format": "uri-reference"
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false
+ },
+ "Header": {
+ "type": "object",
+ "properties": {
+ "description": {
+ "type": "string"
+ },
+ "required": {
+ "type": "boolean",
+ "default": false
+ },
+ "deprecated": {
+ "type": "boolean",
+ "default": false
+ },
+ "allowEmptyValue": {
+ "type": "boolean",
+ "default": false
+ },
+ "style": {
+ "type": "string",
+ "enum": [
+ "simple"
+ ],
+ "default": "simple"
+ },
+ "explode": {
+ "type": "boolean"
+ },
+ "allowReserved": {
+ "type": "boolean",
+ "default": false
+ },
+ "schema": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Schema"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ },
+ "content": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/definitions/MediaType"
+ },
+ "minProperties": 1,
+ "maxProperties": 1
+ },
+ "example": {
+ },
+ "examples": {
+ "type": "object",
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Example"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ }
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false,
+ "allOf": [
+ {
+ "$ref": "#/definitions/ExampleXORExamples"
+ },
+ {
+ "$ref": "#/definitions/SchemaXORContent"
+ }
+ ]
+ },
+ "Paths": {
+ "type": "object",
+ "patternProperties": {
+ "^\\/": {
+ "$ref": "#/definitions/PathItem"
+ },
+ "^x-": {
+ }
+ },
+ "additionalProperties": false
+ },
+ "PathItem": {
+ "type": "object",
+ "properties": {
+ "$ref": {
+ "type": "string"
+ },
+ "summary": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "servers": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Server"
+ }
+ },
+ "parameters": {
+ "type": "array",
+ "items": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Parameter"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ },
+ "uniqueItems": true
+ }
+ },
+ "patternProperties": {
+ "^(get|put|post|delete|options|head|patch|trace)$": {
+ "$ref": "#/definitions/Operation"
+ },
+ "^x-": {
+ }
+ },
+ "additionalProperties": false
+ },
+ "Operation": {
+ "type": "object",
+ "required": [
+ "responses"
+ ],
+ "properties": {
+ "tags": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "summary": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "externalDocs": {
+ "$ref": "#/definitions/ExternalDocumentation"
+ },
+ "operationId": {
+ "type": "string"
+ },
+ "parameters": {
+ "type": "array",
+ "items": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Parameter"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ },
+ "uniqueItems": true
+ },
+ "requestBody": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/RequestBody"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ },
+ "responses": {
+ "$ref": "#/definitions/Responses"
+ },
+ "callbacks": {
+ "type": "object",
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Callback"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ }
+ },
+ "deprecated": {
+ "type": "boolean",
+ "default": false
+ },
+ "security": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/SecurityRequirement"
+ }
+ },
+ "servers": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/Server"
+ }
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false
+ },
+ "Responses": {
+ "type": "object",
+ "properties": {
+ "default": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Response"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ }
+ },
+ "patternProperties": {
+ "^[1-5](?:\\d{2}|XX)$": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Response"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ },
+ "^x-": {
+ }
+ },
+ "minProperties": 1,
+ "additionalProperties": false
+ },
+ "SecurityRequirement": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "Tag": {
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "externalDocs": {
+ "$ref": "#/definitions/ExternalDocumentation"
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false
+ },
+ "ExternalDocumentation": {
+ "type": "object",
+ "required": [
+ "url"
+ ],
+ "properties": {
+ "description": {
+ "type": "string"
+ },
+ "url": {
+ "type": "string",
+ "format": "uri-reference"
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false
+ },
+ "ExampleXORExamples": {
+ "description": "Example and examples are mutually exclusive",
+ "not": {
+ "required": [
+ "example",
+ "examples"
+ ]
+ }
+ },
+ "SchemaXORContent": {
+ "description": "Schema and content are mutually exclusive, at least one is required",
+ "not": {
+ "required": [
+ "schema",
+ "content"
+ ]
+ },
+ "oneOf": [
+ {
+ "required": [
+ "schema"
+ ]
+ },
+ {
+ "required": [
+ "content"
+ ],
+ "description": "Some properties are not allowed if content is present",
+ "allOf": [
+ {
+ "not": {
+ "required": [
+ "style"
+ ]
+ }
+ },
+ {
+ "not": {
+ "required": [
+ "explode"
+ ]
+ }
+ },
+ {
+ "not": {
+ "required": [
+ "allowReserved"
+ ]
+ }
+ },
+ {
+ "not": {
+ "required": [
+ "example"
+ ]
+ }
+ },
+ {
+ "not": {
+ "required": [
+ "examples"
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "Parameter": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "in": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "required": {
+ "type": "boolean",
+ "default": false
+ },
+ "deprecated": {
+ "type": "boolean",
+ "default": false
+ },
+ "allowEmptyValue": {
+ "type": "boolean",
+ "default": false
+ },
+ "style": {
+ "type": "string"
+ },
+ "explode": {
+ "type": "boolean"
+ },
+ "allowReserved": {
+ "type": "boolean",
+ "default": false
+ },
+ "schema": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Schema"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ },
+ "content": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/definitions/MediaType"
+ },
+ "minProperties": 1,
+ "maxProperties": 1
+ },
+ "example": {
+ },
+ "examples": {
+ "type": "object",
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Example"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ }
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "name",
+ "in"
+ ],
+ "allOf": [
+ {
+ "$ref": "#/definitions/ExampleXORExamples"
+ },
+ {
+ "$ref": "#/definitions/SchemaXORContent"
+ },
+ {
+ "$ref": "#/definitions/ParameterLocation"
+ }
+ ]
+ },
+ "ParameterLocation": {
+ "description": "Parameter location",
+ "oneOf": [
+ {
+ "description": "Parameter in path",
+ "required": [
+ "required"
+ ],
+ "properties": {
+ "in": {
+ "enum": [
+ "path"
+ ]
+ },
+ "style": {
+ "enum": [
+ "matrix",
+ "label",
+ "simple"
+ ],
+ "default": "simple"
+ },
+ "required": {
+ "enum": [
+ true
+ ]
+ }
+ }
+ },
+ {
+ "description": "Parameter in query",
+ "properties": {
+ "in": {
+ "enum": [
+ "query"
+ ]
+ },
+ "style": {
+ "enum": [
+ "form",
+ "spaceDelimited",
+ "pipeDelimited",
+ "deepObject"
+ ],
+ "default": "form"
+ }
+ }
+ },
+ {
+ "description": "Parameter in header",
+ "properties": {
+ "in": {
+ "enum": [
+ "header"
+ ]
+ },
+ "style": {
+ "enum": [
+ "simple"
+ ],
+ "default": "simple"
+ }
+ }
+ },
+ {
+ "description": "Parameter in cookie",
+ "properties": {
+ "in": {
+ "enum": [
+ "cookie"
+ ]
+ },
+ "style": {
+ "enum": [
+ "form"
+ ],
+ "default": "form"
+ }
+ }
+ }
+ ]
+ },
+ "RequestBody": {
+ "type": "object",
+ "required": [
+ "content"
+ ],
+ "properties": {
+ "description": {
+ "type": "string"
+ },
+ "content": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/definitions/MediaType"
+ }
+ },
+ "required": {
+ "type": "boolean",
+ "default": false
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false
+ },
+ "SecurityScheme": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/APIKeySecurityScheme"
+ },
+ {
+ "$ref": "#/definitions/HTTPSecurityScheme"
+ },
+ {
+ "$ref": "#/definitions/OAuth2SecurityScheme"
+ },
+ {
+ "$ref": "#/definitions/OpenIdConnectSecurityScheme"
+ }
+ ]
+ },
+ "APIKeySecurityScheme": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "in"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "apiKey"
+ ]
+ },
+ "name": {
+ "type": "string"
+ },
+ "in": {
+ "type": "string",
+ "enum": [
+ "header",
+ "query",
+ "cookie"
+ ]
+ },
+ "description": {
+ "type": "string"
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false
+ },
+ "HTTPSecurityScheme": {
+ "type": "object",
+ "required": [
+ "scheme",
+ "type"
+ ],
+ "properties": {
+ "scheme": {
+ "type": "string"
+ },
+ "bearerFormat": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "http"
+ ]
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false,
+ "oneOf": [
+ {
+ "description": "Bearer",
+ "properties": {
+ "scheme": {
+ "type": "string",
+ "pattern": "^[Bb][Ee][Aa][Rr][Ee][Rr]$"
+ }
+ }
+ },
+ {
+ "description": "Non Bearer",
+ "not": {
+ "required": [
+ "bearerFormat"
+ ]
+ },
+ "properties": {
+ "scheme": {
+ "not": {
+ "type": "string",
+ "pattern": "^[Bb][Ee][Aa][Rr][Ee][Rr]$"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "OAuth2SecurityScheme": {
+ "type": "object",
+ "required": [
+ "type",
+ "flows"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "oauth2"
+ ]
+ },
+ "flows": {
+ "$ref": "#/definitions/OAuthFlows"
+ },
+ "description": {
+ "type": "string"
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false
+ },
+ "OpenIdConnectSecurityScheme": {
+ "type": "object",
+ "required": [
+ "type",
+ "openIdConnectUrl"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "openIdConnect"
+ ]
+ },
+ "openIdConnectUrl": {
+ "type": "string",
+ "format": "uri-reference"
+ },
+ "description": {
+ "type": "string"
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false
+ },
+ "OAuthFlows": {
+ "type": "object",
+ "properties": {
+ "implicit": {
+ "$ref": "#/definitions/ImplicitOAuthFlow"
+ },
+ "password": {
+ "$ref": "#/definitions/PasswordOAuthFlow"
+ },
+ "clientCredentials": {
+ "$ref": "#/definitions/ClientCredentialsFlow"
+ },
+ "authorizationCode": {
+ "$ref": "#/definitions/AuthorizationCodeOAuthFlow"
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false
+ },
+ "ImplicitOAuthFlow": {
+ "type": "object",
+ "required": [
+ "authorizationUrl",
+ "scopes"
+ ],
+ "properties": {
+ "authorizationUrl": {
+ "type": "string",
+ "format": "uri-reference"
+ },
+ "refreshUrl": {
+ "type": "string",
+ "format": "uri-reference"
+ },
+ "scopes": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false
+ },
+ "PasswordOAuthFlow": {
+ "type": "object",
+ "required": [
+ "tokenUrl",
+ "scopes"
+ ],
+ "properties": {
+ "tokenUrl": {
+ "type": "string",
+ "format": "uri-reference"
+ },
+ "refreshUrl": {
+ "type": "string",
+ "format": "uri-reference"
+ },
+ "scopes": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false
+ },
+ "ClientCredentialsFlow": {
+ "type": "object",
+ "required": [
+ "tokenUrl",
+ "scopes"
+ ],
+ "properties": {
+ "tokenUrl": {
+ "type": "string",
+ "format": "uri-reference"
+ },
+ "refreshUrl": {
+ "type": "string",
+ "format": "uri-reference"
+ },
+ "scopes": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false
+ },
+ "AuthorizationCodeOAuthFlow": {
+ "type": "object",
+ "required": [
+ "authorizationUrl",
+ "tokenUrl",
+ "scopes"
+ ],
+ "properties": {
+ "authorizationUrl": {
+ "type": "string",
+ "format": "uri-reference"
+ },
+ "tokenUrl": {
+ "type": "string",
+ "format": "uri-reference"
+ },
+ "refreshUrl": {
+ "type": "string",
+ "format": "uri-reference"
+ },
+ "scopes": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false
+ },
+ "Link": {
+ "type": "object",
+ "properties": {
+ "operationId": {
+ "type": "string"
+ },
+ "operationRef": {
+ "type": "string",
+ "format": "uri-reference"
+ },
+ "parameters": {
+ "type": "object",
+ "additionalProperties": {
+ }
+ },
+ "requestBody": {
+ },
+ "description": {
+ "type": "string"
+ },
+ "server": {
+ "$ref": "#/definitions/Server"
+ }
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ },
+ "additionalProperties": false,
+ "not": {
+ "description": "Operation Id and Operation Ref are mutually exclusive",
+ "required": [
+ "operationId",
+ "operationRef"
+ ]
+ }
+ },
+ "Callback": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/definitions/PathItem"
+ },
+ "patternProperties": {
+ "^x-": {
+ }
+ }
+ },
+ "Encoding": {
+ "type": "object",
+ "properties": {
+ "contentType": {
+ "type": "string"
+ },
+ "headers": {
+ "type": "object",
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/Header"
+ },
+ {
+ "$ref": "#/definitions/Reference"
+ }
+ ]
+ }
+ },
+ "style": {
+ "type": "string",
+ "enum": [
+ "form",
+ "spaceDelimited",
+ "pipeDelimited",
+ "deepObject"
+ ]
+ },
+ "explode": {
+ "type": "boolean"
+ },
+ "allowReserved": {
+ "type": "boolean",
+ "default": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+}
diff --git a/src/test/resources/schema_definition_validation/OpenAPI3_1.json b/src/test/resources/schema_definition_validation/OpenAPI3_1.json
new file mode 100644
index 00000000..468bc7e5
--- /dev/null
+++ b/src/test/resources/schema_definition_validation/OpenAPI3_1.json
@@ -0,0 +1,1440 @@
+{
+ "$id": "https://spec.openapis.org/oas/3.1/schema/2022-10-07",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "description": "The description of OpenAPI v3.1.x documents without schema validation, as defined by https://spec.openapis.org/oas/v3.1.0",
+ "type": "object",
+ "properties": {
+ "openapi": {
+ "type": "string",
+ "pattern": "^3\\.1\\.\\d+(-.+)?$"
+ },
+ "info": {
+ "$ref": "#/$defs/info"
+ },
+ "jsonSchemaDialect": {
+ "type": "string",
+ "format": "uri",
+ "default": "https://spec.openapis.org/oas/3.1/dialect/base"
+ },
+ "servers": {
+ "type": "array",
+ "items": {
+ "$ref": "#/$defs/server"
+ },
+ "default": [
+ {
+ "url": "/"
+ }
+ ]
+ },
+ "paths": {
+ "$ref": "#/$defs/paths"
+ },
+ "webhooks": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/$defs/path-item-or-reference"
+ }
+ },
+ "components": {
+ "$ref": "#/$defs/components"
+ },
+ "security": {
+ "type": "array",
+ "items": {
+ "$ref": "#/$defs/security-requirement"
+ }
+ },
+ "tags": {
+ "type": "array",
+ "items": {
+ "$ref": "#/$defs/tag"
+ }
+ },
+ "externalDocs": {
+ "$ref": "#/$defs/external-documentation"
+ }
+ },
+ "required": [
+ "openapi",
+ "info"
+ ],
+ "anyOf": [
+ {
+ "required": [
+ "paths"
+ ]
+ },
+ {
+ "required": [
+ "components"
+ ]
+ },
+ {
+ "required": [
+ "webhooks"
+ ]
+ }
+ ],
+ "$ref": "#/$defs/specification-extensions",
+ "unevaluatedProperties": false,
+ "$defs": {
+ "info": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#info-object",
+ "type": "object",
+ "properties": {
+ "title": {
+ "type": "string"
+ },
+ "summary": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "termsOfService": {
+ "type": "string",
+ "format": "uri"
+ },
+ "contact": {
+ "$ref": "#/$defs/contact"
+ },
+ "license": {
+ "$ref": "#/$defs/license"
+ },
+ "version": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "title",
+ "version"
+ ],
+ "$ref": "#/$defs/specification-extensions",
+ "unevaluatedProperties": false
+ },
+ "contact": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#contact-object",
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "url": {
+ "type": "string",
+ "format": "uri"
+ },
+ "email": {
+ "type": "string",
+ "format": "email"
+ }
+ },
+ "$ref": "#/$defs/specification-extensions",
+ "unevaluatedProperties": false
+ },
+ "license": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#license-object",
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "identifier": {
+ "type": "string"
+ },
+ "url": {
+ "type": "string",
+ "format": "uri"
+ }
+ },
+ "required": [
+ "name"
+ ],
+ "dependentSchemas": {
+ "identifier": {
+ "not": {
+ "required": [
+ "url"
+ ]
+ }
+ }
+ },
+ "$ref": "#/$defs/specification-extensions",
+ "unevaluatedProperties": false
+ },
+ "server": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#server-object",
+ "type": "object",
+ "properties": {
+ "url": {
+ "type": "string",
+ "format": "uri-reference"
+ },
+ "description": {
+ "type": "string"
+ },
+ "variables": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/$defs/server-variable"
+ }
+ }
+ },
+ "required": [
+ "url"
+ ],
+ "$ref": "#/$defs/specification-extensions",
+ "unevaluatedProperties": false
+ },
+ "server-variable": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#server-variable-object",
+ "type": "object",
+ "properties": {
+ "enum": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "minItems": 1
+ },
+ "default": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "default"
+ ],
+ "$ref": "#/$defs/specification-extensions",
+ "unevaluatedProperties": false
+ },
+ "components": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#components-object",
+ "type": "object",
+ "properties": {
+ "schemas": {
+ "type": "object",
+ "additionalProperties": {
+ "$dynamicRef": "#meta"
+ }
+ },
+ "responses": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/$defs/response-or-reference"
+ }
+ },
+ "parameters": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/$defs/parameter-or-reference"
+ }
+ },
+ "examples": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/$defs/example-or-reference"
+ }
+ },
+ "requestBodies": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/$defs/request-body-or-reference"
+ }
+ },
+ "headers": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/$defs/header-or-reference"
+ }
+ },
+ "securitySchemes": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/$defs/security-scheme-or-reference"
+ }
+ },
+ "links": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/$defs/link-or-reference"
+ }
+ },
+ "callbacks": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/$defs/callbacks-or-reference"
+ }
+ },
+ "pathItems": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/$defs/path-item-or-reference"
+ }
+ }
+ },
+ "patternProperties": {
+ "^(schemas|responses|parameters|examples|requestBodies|headers|securitySchemes|links|callbacks|pathItems)$": {
+ "$comment": "Enumerating all of the property names in the regex above is necessary for unevaluatedProperties to work as expected",
+ "propertyNames": {
+ "pattern": "^[a-zA-Z0-9._-]+$"
+ }
+ }
+ },
+ "$ref": "#/$defs/specification-extensions",
+ "unevaluatedProperties": false
+ },
+ "paths": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#paths-object",
+ "type": "object",
+ "patternProperties": {
+ "^/": {
+ "$ref": "#/$defs/path-item"
+ }
+ },
+ "$ref": "#/$defs/specification-extensions",
+ "unevaluatedProperties": false
+ },
+ "path-item": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#path-item-object",
+ "type": "object",
+ "properties": {
+ "summary": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "servers": {
+ "type": "array",
+ "items": {
+ "$ref": "#/$defs/server"
+ }
+ },
+ "parameters": {
+ "type": "array",
+ "items": {
+ "$ref": "#/$defs/parameter-or-reference"
+ }
+ },
+ "get": {
+ "$ref": "#/$defs/operation"
+ },
+ "put": {
+ "$ref": "#/$defs/operation"
+ },
+ "post": {
+ "$ref": "#/$defs/operation"
+ },
+ "delete": {
+ "$ref": "#/$defs/operation"
+ },
+ "options": {
+ "$ref": "#/$defs/operation"
+ },
+ "head": {
+ "$ref": "#/$defs/operation"
+ },
+ "patch": {
+ "$ref": "#/$defs/operation"
+ },
+ "trace": {
+ "$ref": "#/$defs/operation"
+ }
+ },
+ "$ref": "#/$defs/specification-extensions",
+ "unevaluatedProperties": false
+ },
+ "path-item-or-reference": {
+ "if": {
+ "type": "object",
+ "required": [
+ "$ref"
+ ]
+ },
+ "then": {
+ "$ref": "#/$defs/reference"
+ },
+ "else": {
+ "$ref": "#/$defs/path-item"
+ }
+ },
+ "operation": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#operation-object",
+ "type": "object",
+ "properties": {
+ "tags": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "summary": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "externalDocs": {
+ "$ref": "#/$defs/external-documentation"
+ },
+ "operationId": {
+ "type": "string"
+ },
+ "parameters": {
+ "type": "array",
+ "items": {
+ "$ref": "#/$defs/parameter-or-reference"
+ }
+ },
+ "requestBody": {
+ "$ref": "#/$defs/request-body-or-reference"
+ },
+ "responses": {
+ "$ref": "#/$defs/responses"
+ },
+ "callbacks": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/$defs/callbacks-or-reference"
+ }
+ },
+ "deprecated": {
+ "default": false,
+ "type": "boolean"
+ },
+ "security": {
+ "type": "array",
+ "items": {
+ "$ref": "#/$defs/security-requirement"
+ }
+ },
+ "servers": {
+ "type": "array",
+ "items": {
+ "$ref": "#/$defs/server"
+ }
+ }
+ },
+ "$ref": "#/$defs/specification-extensions",
+ "unevaluatedProperties": false
+ },
+ "external-documentation": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#external-documentation-object",
+ "type": "object",
+ "properties": {
+ "description": {
+ "type": "string"
+ },
+ "url": {
+ "type": "string",
+ "format": "uri"
+ }
+ },
+ "required": [
+ "url"
+ ],
+ "$ref": "#/$defs/specification-extensions",
+ "unevaluatedProperties": false
+ },
+ "parameter": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#parameter-object",
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "in": {
+ "enum": [
+ "query",
+ "header",
+ "path",
+ "cookie"
+ ]
+ },
+ "description": {
+ "type": "string"
+ },
+ "required": {
+ "default": false,
+ "type": "boolean"
+ },
+ "deprecated": {
+ "default": false,
+ "type": "boolean"
+ },
+ "schema": {
+ "$dynamicRef": "#meta"
+ },
+ "content": {
+ "$ref": "#/$defs/content",
+ "minProperties": 1,
+ "maxProperties": 1
+ }
+ },
+ "required": [
+ "name",
+ "in"
+ ],
+ "oneOf": [
+ {
+ "required": [
+ "schema"
+ ]
+ },
+ {
+ "required": [
+ "content"
+ ]
+ }
+ ],
+ "if": {
+ "properties": {
+ "in": {
+ "const": "query"
+ }
+ },
+ "required": [
+ "in"
+ ]
+ },
+ "then": {
+ "properties": {
+ "allowEmptyValue": {
+ "default": false,
+ "type": "boolean"
+ }
+ }
+ },
+ "dependentSchemas": {
+ "schema": {
+ "properties": {
+ "style": {
+ "type": "string"
+ },
+ "explode": {
+ "type": "boolean"
+ }
+ },
+ "allOf": [
+ {
+ "$ref": "#/$defs/examples"
+ },
+ {
+ "$ref": "#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-path"
+ },
+ {
+ "$ref": "#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-header"
+ },
+ {
+ "$ref": "#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-query"
+ },
+ {
+ "$ref": "#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-cookie"
+ },
+ {
+ "$ref": "#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-form"
+ }
+ ],
+ "$defs": {
+ "styles-for-path": {
+ "if": {
+ "properties": {
+ "in": {
+ "const": "path"
+ }
+ },
+ "required": [
+ "in"
+ ]
+ },
+ "then": {
+ "properties": {
+ "name": {
+ "pattern": "[^/#?]+$"
+ },
+ "style": {
+ "default": "simple",
+ "enum": [
+ "matrix",
+ "label",
+ "simple"
+ ]
+ },
+ "required": {
+ "const": true
+ }
+ },
+ "required": [
+ "required"
+ ]
+ }
+ },
+ "styles-for-header": {
+ "if": {
+ "properties": {
+ "in": {
+ "const": "header"
+ }
+ },
+ "required": [
+ "in"
+ ]
+ },
+ "then": {
+ "properties": {
+ "style": {
+ "default": "simple",
+ "const": "simple"
+ }
+ }
+ }
+ },
+ "styles-for-query": {
+ "if": {
+ "properties": {
+ "in": {
+ "const": "query"
+ }
+ },
+ "required": [
+ "in"
+ ]
+ },
+ "then": {
+ "properties": {
+ "style": {
+ "default": "form",
+ "enum": [
+ "form",
+ "spaceDelimited",
+ "pipeDelimited",
+ "deepObject"
+ ]
+ },
+ "allowReserved": {
+ "default": false,
+ "type": "boolean"
+ }
+ }
+ }
+ },
+ "styles-for-cookie": {
+ "if": {
+ "properties": {
+ "in": {
+ "const": "cookie"
+ }
+ },
+ "required": [
+ "in"
+ ]
+ },
+ "then": {
+ "properties": {
+ "style": {
+ "default": "form",
+ "const": "form"
+ }
+ }
+ }
+ },
+ "styles-for-form": {
+ "if": {
+ "properties": {
+ "style": {
+ "const": "form"
+ }
+ },
+ "required": [
+ "style"
+ ]
+ },
+ "then": {
+ "properties": {
+ "explode": {
+ "default": true
+ }
+ }
+ },
+ "else": {
+ "properties": {
+ "explode": {
+ "default": false
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "$ref": "#/$defs/specification-extensions",
+ "unevaluatedProperties": false
+ },
+ "parameter-or-reference": {
+ "if": {
+ "type": "object",
+ "required": [
+ "$ref"
+ ]
+ },
+ "then": {
+ "$ref": "#/$defs/reference"
+ },
+ "else": {
+ "$ref": "#/$defs/parameter"
+ }
+ },
+ "request-body": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#request-body-object",
+ "type": "object",
+ "properties": {
+ "description": {
+ "type": "string"
+ },
+ "content": {
+ "$ref": "#/$defs/content"
+ },
+ "required": {
+ "default": false,
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "content"
+ ],
+ "$ref": "#/$defs/specification-extensions",
+ "unevaluatedProperties": false
+ },
+ "request-body-or-reference": {
+ "if": {
+ "type": "object",
+ "required": [
+ "$ref"
+ ]
+ },
+ "then": {
+ "$ref": "#/$defs/reference"
+ },
+ "else": {
+ "$ref": "#/$defs/request-body"
+ }
+ },
+ "content": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#fixed-fields-10",
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/$defs/media-type"
+ },
+ "propertyNames": {
+ "format": "media-range"
+ }
+ },
+ "media-type": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#media-type-object",
+ "type": "object",
+ "properties": {
+ "schema": {
+ "$dynamicRef": "#meta"
+ },
+ "encoding": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/$defs/encoding"
+ }
+ }
+ },
+ "allOf": [
+ {
+ "$ref": "#/$defs/specification-extensions"
+ },
+ {
+ "$ref": "#/$defs/examples"
+ }
+ ],
+ "unevaluatedProperties": false
+ },
+ "encoding": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#encoding-object",
+ "type": "object",
+ "properties": {
+ "contentType": {
+ "type": "string",
+ "format": "media-range"
+ },
+ "headers": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/$defs/header-or-reference"
+ }
+ },
+ "style": {
+ "default": "form",
+ "enum": [
+ "form",
+ "spaceDelimited",
+ "pipeDelimited",
+ "deepObject"
+ ]
+ },
+ "explode": {
+ "type": "boolean"
+ },
+ "allowReserved": {
+ "default": false,
+ "type": "boolean"
+ }
+ },
+ "allOf": [
+ {
+ "$ref": "#/$defs/specification-extensions"
+ },
+ {
+ "$ref": "#/$defs/encoding/$defs/explode-default"
+ }
+ ],
+ "unevaluatedProperties": false,
+ "$defs": {
+ "explode-default": {
+ "if": {
+ "properties": {
+ "style": {
+ "const": "form"
+ }
+ },
+ "required": [
+ "style"
+ ]
+ },
+ "then": {
+ "properties": {
+ "explode": {
+ "default": true
+ }
+ }
+ },
+ "else": {
+ "properties": {
+ "explode": {
+ "default": false
+ }
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#responses-object",
+ "type": "object",
+ "properties": {
+ "default": {
+ "$ref": "#/$defs/response-or-reference"
+ }
+ },
+ "patternProperties": {
+ "^[1-5](?:[0-9]{2}|XX)$": {
+ "$ref": "#/$defs/response-or-reference"
+ }
+ },
+ "minProperties": 1,
+ "$ref": "#/$defs/specification-extensions",
+ "unevaluatedProperties": false
+ },
+ "response": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#response-object",
+ "type": "object",
+ "properties": {
+ "description": {
+ "type": "string"
+ },
+ "headers": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/$defs/header-or-reference"
+ }
+ },
+ "content": {
+ "$ref": "#/$defs/content"
+ },
+ "links": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/$defs/link-or-reference"
+ }
+ }
+ },
+ "required": [
+ "description"
+ ],
+ "$ref": "#/$defs/specification-extensions",
+ "unevaluatedProperties": false
+ },
+ "response-or-reference": {
+ "if": {
+ "type": "object",
+ "required": [
+ "$ref"
+ ]
+ },
+ "then": {
+ "$ref": "#/$defs/reference"
+ },
+ "else": {
+ "$ref": "#/$defs/response"
+ }
+ },
+ "callbacks": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#callback-object",
+ "type": "object",
+ "$ref": "#/$defs/specification-extensions",
+ "additionalProperties": {
+ "$ref": "#/$defs/path-item-or-reference"
+ }
+ },
+ "callbacks-or-reference": {
+ "if": {
+ "type": "object",
+ "required": [
+ "$ref"
+ ]
+ },
+ "then": {
+ "$ref": "#/$defs/reference"
+ },
+ "else": {
+ "$ref": "#/$defs/callbacks"
+ }
+ },
+ "example": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#example-object",
+ "type": "object",
+ "properties": {
+ "summary": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "value": true,
+ "externalValue": {
+ "type": "string",
+ "format": "uri"
+ }
+ },
+ "not": {
+ "required": [
+ "value",
+ "externalValue"
+ ]
+ },
+ "$ref": "#/$defs/specification-extensions",
+ "unevaluatedProperties": false
+ },
+ "example-or-reference": {
+ "if": {
+ "type": "object",
+ "required": [
+ "$ref"
+ ]
+ },
+ "then": {
+ "$ref": "#/$defs/reference"
+ },
+ "else": {
+ "$ref": "#/$defs/example"
+ }
+ },
+ "link": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#link-object",
+ "type": "object",
+ "properties": {
+ "operationRef": {
+ "type": "string",
+ "format": "uri-reference"
+ },
+ "operationId": {
+ "type": "string"
+ },
+ "parameters": {
+ "$ref": "#/$defs/map-of-strings"
+ },
+ "requestBody": true,
+ "description": {
+ "type": "string"
+ },
+ "body": {
+ "$ref": "#/$defs/server"
+ }
+ },
+ "oneOf": [
+ {
+ "required": [
+ "operationRef"
+ ]
+ },
+ {
+ "required": [
+ "operationId"
+ ]
+ }
+ ],
+ "$ref": "#/$defs/specification-extensions",
+ "unevaluatedProperties": false
+ },
+ "link-or-reference": {
+ "if": {
+ "type": "object",
+ "required": [
+ "$ref"
+ ]
+ },
+ "then": {
+ "$ref": "#/$defs/reference"
+ },
+ "else": {
+ "$ref": "#/$defs/link"
+ }
+ },
+ "header": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#header-object",
+ "type": "object",
+ "properties": {
+ "description": {
+ "type": "string"
+ },
+ "required": {
+ "default": false,
+ "type": "boolean"
+ },
+ "deprecated": {
+ "default": false,
+ "type": "boolean"
+ },
+ "schema": {
+ "$dynamicRef": "#meta"
+ },
+ "content": {
+ "$ref": "#/$defs/content",
+ "minProperties": 1,
+ "maxProperties": 1
+ }
+ },
+ "oneOf": [
+ {
+ "required": [
+ "schema"
+ ]
+ },
+ {
+ "required": [
+ "content"
+ ]
+ }
+ ],
+ "dependentSchemas": {
+ "schema": {
+ "properties": {
+ "style": {
+ "default": "simple",
+ "const": "simple"
+ },
+ "explode": {
+ "default": false,
+ "type": "boolean"
+ }
+ },
+ "$ref": "#/$defs/examples"
+ }
+ },
+ "$ref": "#/$defs/specification-extensions",
+ "unevaluatedProperties": false
+ },
+ "header-or-reference": {
+ "if": {
+ "type": "object",
+ "required": [
+ "$ref"
+ ]
+ },
+ "then": {
+ "$ref": "#/$defs/reference"
+ },
+ "else": {
+ "$ref": "#/$defs/header"
+ }
+ },
+ "tag": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#tag-object",
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "externalDocs": {
+ "$ref": "#/$defs/external-documentation"
+ }
+ },
+ "required": [
+ "name"
+ ],
+ "$ref": "#/$defs/specification-extensions",
+ "unevaluatedProperties": false
+ },
+ "reference": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#reference-object",
+ "type": "object",
+ "properties": {
+ "$ref": {
+ "type": "string",
+ "format": "uri-reference"
+ },
+ "summary": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ }
+ },
+ "unevaluatedProperties": false
+ },
+ "schema": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#schema-object",
+ "$dynamicAnchor": "meta",
+ "type": [
+ "object",
+ "boolean"
+ ]
+ },
+ "security-scheme": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#security-scheme-object",
+ "type": "object",
+ "properties": {
+ "type": {
+ "enum": [
+ "apiKey",
+ "http",
+ "mutualTLS",
+ "oauth2",
+ "openIdConnect"
+ ]
+ },
+ "description": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "allOf": [
+ {
+ "$ref": "#/$defs/specification-extensions"
+ },
+ {
+ "$ref": "#/$defs/security-scheme/$defs/type-apikey"
+ },
+ {
+ "$ref": "#/$defs/security-scheme/$defs/type-http"
+ },
+ {
+ "$ref": "#/$defs/security-scheme/$defs/type-http-bearer"
+ },
+ {
+ "$ref": "#/$defs/security-scheme/$defs/type-oauth2"
+ },
+ {
+ "$ref": "#/$defs/security-scheme/$defs/type-oidc"
+ }
+ ],
+ "unevaluatedProperties": false,
+ "$defs": {
+ "type-apikey": {
+ "if": {
+ "properties": {
+ "type": {
+ "const": "apiKey"
+ }
+ },
+ "required": [
+ "type"
+ ]
+ },
+ "then": {
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "in": {
+ "enum": [
+ "query",
+ "header",
+ "cookie"
+ ]
+ }
+ },
+ "required": [
+ "name",
+ "in"
+ ]
+ }
+ },
+ "type-http": {
+ "if": {
+ "properties": {
+ "type": {
+ "const": "http"
+ }
+ },
+ "required": [
+ "type"
+ ]
+ },
+ "then": {
+ "properties": {
+ "scheme": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "scheme"
+ ]
+ }
+ },
+ "type-http-bearer": {
+ "if": {
+ "properties": {
+ "type": {
+ "const": "http"
+ },
+ "scheme": {
+ "type": "string",
+ "pattern": "^[Bb][Ee][Aa][Rr][Ee][Rr]$"
+ }
+ },
+ "required": [
+ "type",
+ "scheme"
+ ]
+ },
+ "then": {
+ "properties": {
+ "bearerFormat": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "type-oauth2": {
+ "if": {
+ "properties": {
+ "type": {
+ "const": "oauth2"
+ }
+ },
+ "required": [
+ "type"
+ ]
+ },
+ "then": {
+ "properties": {
+ "flows": {
+ "$ref": "#/$defs/oauth-flows"
+ }
+ },
+ "required": [
+ "flows"
+ ]
+ }
+ },
+ "type-oidc": {
+ "if": {
+ "properties": {
+ "type": {
+ "const": "openIdConnect"
+ }
+ },
+ "required": [
+ "type"
+ ]
+ },
+ "then": {
+ "properties": {
+ "openIdConnectUrl": {
+ "type": "string",
+ "format": "uri"
+ }
+ },
+ "required": [
+ "openIdConnectUrl"
+ ]
+ }
+ }
+ }
+ },
+ "security-scheme-or-reference": {
+ "if": {
+ "type": "object",
+ "required": [
+ "$ref"
+ ]
+ },
+ "then": {
+ "$ref": "#/$defs/reference"
+ },
+ "else": {
+ "$ref": "#/$defs/security-scheme"
+ }
+ },
+ "oauth-flows": {
+ "type": "object",
+ "properties": {
+ "implicit": {
+ "$ref": "#/$defs/oauth-flows/$defs/implicit"
+ },
+ "password": {
+ "$ref": "#/$defs/oauth-flows/$defs/password"
+ },
+ "clientCredentials": {
+ "$ref": "#/$defs/oauth-flows/$defs/client-credentials"
+ },
+ "authorizationCode": {
+ "$ref": "#/$defs/oauth-flows/$defs/authorization-code"
+ }
+ },
+ "$ref": "#/$defs/specification-extensions",
+ "unevaluatedProperties": false,
+ "$defs": {
+ "implicit": {
+ "type": "object",
+ "properties": {
+ "authorizationUrl": {
+ "type": "string",
+ "format": "uri"
+ },
+ "refreshUrl": {
+ "type": "string",
+ "format": "uri"
+ },
+ "scopes": {
+ "$ref": "#/$defs/map-of-strings"
+ }
+ },
+ "required": [
+ "authorizationUrl",
+ "scopes"
+ ],
+ "$ref": "#/$defs/specification-extensions",
+ "unevaluatedProperties": false
+ },
+ "password": {
+ "type": "object",
+ "properties": {
+ "tokenUrl": {
+ "type": "string",
+ "format": "uri"
+ },
+ "refreshUrl": {
+ "type": "string",
+ "format": "uri"
+ },
+ "scopes": {
+ "$ref": "#/$defs/map-of-strings"
+ }
+ },
+ "required": [
+ "tokenUrl",
+ "scopes"
+ ],
+ "$ref": "#/$defs/specification-extensions",
+ "unevaluatedProperties": false
+ },
+ "client-credentials": {
+ "type": "object",
+ "properties": {
+ "tokenUrl": {
+ "type": "string",
+ "format": "uri"
+ },
+ "refreshUrl": {
+ "type": "string",
+ "format": "uri"
+ },
+ "scopes": {
+ "$ref": "#/$defs/map-of-strings"
+ }
+ },
+ "required": [
+ "tokenUrl",
+ "scopes"
+ ],
+ "$ref": "#/$defs/specification-extensions",
+ "unevaluatedProperties": false
+ },
+ "authorization-code": {
+ "type": "object",
+ "properties": {
+ "authorizationUrl": {
+ "type": "string",
+ "format": "uri"
+ },
+ "tokenUrl": {
+ "type": "string",
+ "format": "uri"
+ },
+ "refreshUrl": {
+ "type": "string",
+ "format": "uri"
+ },
+ "scopes": {
+ "$ref": "#/$defs/map-of-strings"
+ }
+ },
+ "required": [
+ "authorizationUrl",
+ "tokenUrl",
+ "scopes"
+ ],
+ "$ref": "#/$defs/specification-extensions",
+ "unevaluatedProperties": false
+ }
+ }
+ },
+ "security-requirement": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#security-requirement-object",
+ "type": "object",
+ "additionalProperties": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "specification-extensions": {
+ "$comment": "https://spec.openapis.org/oas/v3.1.0#specification-extensions",
+ "patternProperties": {
+ "^x-": true
+ }
+ },
+ "examples": {
+ "properties": {
+ "example": true,
+ "examples": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/$defs/example-or-reference"
+ }
+ }
+ }
+ },
+ "map-of-strings": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ }
+ }
+}
diff --git a/src/test/resources/schema_definition_validation/angular_cli_workspace_schema.json b/src/test/resources/schema_definition_validation/angular_cli_workspace_schema.json
new file mode 100644
index 00000000..433fbea3
--- /dev/null
+++ b/src/test/resources/schema_definition_validation/angular_cli_workspace_schema.json
@@ -0,0 +1,630 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema",
+ "$id": "ng-cli://config/schema.json",
+ "title": "Angular CLI Workspace Configuration",
+ "type": "object",
+ "properties": {
+ "$schema": {
+ "type": "string"
+ },
+ "version": {
+ "$ref": "#/definitions/fileVersion"
+ },
+ "cli": {
+ "$ref": "#/definitions/cliOptions"
+ },
+ "schematics": {
+ "$ref": "#/definitions/schematicOptions"
+ },
+ "newProjectRoot": {
+ "type": "string",
+ "description": "Path where new projects will be created."
+ },
+ "defaultProject": {
+ "type": "string",
+ "description": "Default project name used in commands.",
+ "x-deprecated": "The project to use will be determined from the current working directory."
+ },
+ "projects": {
+ "type": "object",
+ "patternProperties": {
+ "^(?:@[a-zA-Z0-9_-]+/)?[a-zA-Z0-9_-]+$": {
+ "$ref": "#/definitions/project"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false,
+ "required": ["version"],
+ "definitions": {
+ "cliOptions": {
+ "type": "object",
+ "properties": {
+ "defaultCollection": {
+ "description": "The default schematics collection to use.",
+ "type": "string",
+ "x-deprecated": "Use 'schematicCollections' instead."
+ },
+ "schematicCollections": {
+ "type": "array",
+ "description": "The list of schematic collections to use.",
+ "items": {
+ "type": "string",
+ "uniqueItems": true
+ }
+ },
+ "packageManager": {
+ "description": "Specify which package manager tool to use.",
+ "type": "string",
+ "enum": ["npm", "cnpm", "yarn", "pnpm"]
+ },
+ "warnings": {
+ "description": "Control CLI specific console warnings",
+ "type": "object",
+ "properties": {
+ "versionMismatch": {
+ "description": "Show a warning when the global version is newer than the local one.",
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false
+ },
+ "analytics": {
+ "type": ["boolean", "string"],
+ "description": "Share pseudonymous usage data with the Angular Team at Google."
+ },
+ "cache": {
+ "description": "Control disk cache.",
+ "type": "object",
+ "properties": {
+ "environment": {
+ "description": "Configure in which environment disk cache is enabled.",
+ "type": "string",
+ "enum": ["local", "ci", "all"]
+ },
+ "enabled": {
+ "description": "Configure whether disk caching is enabled.",
+ "type": "boolean"
+ },
+ "path": {
+ "description": "Cache base path.",
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "cliGlobalOptions": {
+ "type": "object",
+ "properties": {
+ "defaultCollection": {
+ "description": "The default schematics collection to use.",
+ "type": "string",
+ "x-deprecated": "Use 'schematicCollections' instead."
+ },
+ "schematicCollections": {
+ "type": "array",
+ "description": "The list of schematic collections to use.",
+ "items": {
+ "type": "string",
+ "uniqueItems": true
+ }
+ },
+ "packageManager": {
+ "description": "Specify which package manager tool to use.",
+ "type": "string",
+ "enum": ["npm", "cnpm", "yarn", "pnpm"]
+ },
+ "warnings": {
+ "description": "Control CLI specific console warnings",
+ "type": "object",
+ "properties": {
+ "versionMismatch": {
+ "description": "Show a warning when the global version is newer than the local one.",
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false
+ },
+ "analytics": {
+ "type": ["boolean", "string"],
+ "description": "Share pseudonymous usage data with the Angular Team at Google."
+ },
+ "completion": {
+ "type": "object",
+ "description": "Angular CLI completion settings.",
+ "properties": {
+ "prompted": {
+ "type": "boolean",
+ "description": "Whether the user has been prompted to add completion command prompt."
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "schematicOptions": {
+ "type": "object",
+ "properties": {
+ "@schematics/angular:application": {
+ "$ref": "../../../../schematics/angular/application/schema.json"
+ },
+ "@schematics/angular:class": {
+ "$ref": "../../../../schematics/angular/class/schema.json"
+ },
+ "@schematics/angular:component": {
+ "$ref": "../../../../schematics/angular/component/schema.json"
+ },
+ "@schematics/angular:directive": {
+ "$ref": "../../../../schematics/angular/directive/schema.json"
+ },
+ "@schematics/angular:enum": {
+ "$ref": "../../../../schematics/angular/enum/schema.json"
+ },
+ "@schematics/angular:guard": {
+ "$ref": "../../../../schematics/angular/guard/schema.json"
+ },
+ "@schematics/angular:interceptor": {
+ "$ref": "../../../../schematics/angular/interceptor/schema.json"
+ },
+ "@schematics/angular:interface": {
+ "$ref": "../../../../schematics/angular/interface/schema.json"
+ },
+ "@schematics/angular:library": {
+ "$ref": "../../../../schematics/angular/library/schema.json"
+ },
+ "@schematics/angular:pipe": {
+ "$ref": "../../../../schematics/angular/pipe/schema.json"
+ },
+ "@schematics/angular:ng-new": {
+ "$ref": "../../../../schematics/angular/ng-new/schema.json"
+ },
+ "@schematics/angular:resolver": {
+ "$ref": "../../../../schematics/angular/resolver/schema.json"
+ },
+ "@schematics/angular:service": {
+ "$ref": "../../../../schematics/angular/service/schema.json"
+ },
+ "@schematics/angular:web-worker": {
+ "$ref": "../../../../schematics/angular/web-worker/schema.json"
+ }
+ },
+ "additionalProperties": {
+ "type": "object"
+ }
+ },
+ "fileVersion": {
+ "type": "integer",
+ "description": "File format version",
+ "minimum": 1
+ },
+ "project": {
+ "type": "object",
+ "properties": {
+ "cli": {
+ "defaultCollection": {
+ "description": "The default schematics collection to use.",
+ "type": "string",
+ "x-deprecated": "Use 'schematicCollections' instead."
+ },
+ "schematicCollections": {
+ "type": "array",
+ "description": "The list of schematic collections to use.",
+ "items": {
+ "type": "string",
+ "uniqueItems": true
+ }
+ }
+ },
+ "schematics": {
+ "$ref": "#/definitions/schematicOptions"
+ },
+ "prefix": {
+ "type": "string",
+ "format": "html-selector",
+ "description": "The prefix to apply to generated selectors."
+ },
+ "root": {
+ "type": "string",
+ "description": "Root of the project files."
+ },
+ "i18n": {
+ "$ref": "#/definitions/project/definitions/i18n"
+ },
+ "sourceRoot": {
+ "type": "string",
+ "description": "The root of the source files, assets and index.html file structure."
+ },
+ "projectType": {
+ "type": "string",
+ "description": "Project type.",
+ "enum": ["application", "library"]
+ },
+ "architect": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/definitions/project/definitions/target"
+ }
+ },
+ "targets": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/definitions/project/definitions/target"
+ }
+ }
+ },
+ "required": ["root", "projectType"],
+ "anyOf": [
+ {
+ "required": ["architect"],
+ "not": {
+ "required": ["targets"]
+ }
+ },
+ {
+ "required": ["targets"],
+ "not": {
+ "required": ["architect"]
+ }
+ },
+ {
+ "not": {
+ "required": ["targets", "architect"]
+ }
+ }
+ ],
+ "additionalProperties": false,
+ "patternProperties": {
+ "^[a-z]{1,3}-.*": {}
+ },
+ "definitions": {
+ "i18n": {
+ "description": "Project i18n options",
+ "type": "object",
+ "properties": {
+ "sourceLocale": {
+ "oneOf": [
+ {
+ "type": "string",
+ "description": "Specifies the source locale of the application.",
+ "default": "en-US",
+ "$comment": "IETF BCP 47 language tag (simplified)",
+ "pattern": "^[a-zA-Z]{2,3}(-[a-zA-Z]{4})?(-([a-zA-Z]{2}|[0-9]{3}))?(-[a-zA-Z]{5,8})?(-x(-[a-zA-Z0-9]{1,8})+)?$"
+ },
+ {
+ "type": "object",
+ "description": "Localization options to use for the source locale",
+ "properties": {
+ "code": {
+ "type": "string",
+ "description": "Specifies the locale code of the source locale",
+ "pattern": "^[a-zA-Z]{2,3}(-[a-zA-Z]{4})?(-([a-zA-Z]{2}|[0-9]{3}))?(-[a-zA-Z]{5,8})?(-x(-[a-zA-Z0-9]{1,8})+)?$"
+ },
+ "baseHref": {
+ "type": "string",
+ "description": "HTML base HREF to use for the locale (defaults to the locale code)"
+ }
+ },
+ "additionalProperties": false
+ }
+ ]
+ },
+ "locales": {
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^[a-zA-Z]{2,3}(-[a-zA-Z]{4})?(-([a-zA-Z]{2}|[0-9]{3}))?(-[a-zA-Z]{5,8})?(-x(-[a-zA-Z0-9]{1,8})+)?$": {
+ "oneOf": [
+ {
+ "type": "string",
+ "description": "Localization file to use for i18n"
+ },
+ {
+ "type": "array",
+ "description": "Localization files to use for i18n",
+ "items": {
+ "type": "string",
+ "uniqueItems": true
+ }
+ },
+ {
+ "type": "object",
+ "description": "Localization options to use for the locale",
+ "properties": {
+ "translation": {
+ "oneOf": [
+ {
+ "type": "string",
+ "description": "Localization file to use for i18n"
+ },
+ {
+ "type": "array",
+ "description": "Localization files to use for i18n",
+ "items": {
+ "type": "string",
+ "uniqueItems": true
+ }
+ }
+ ]
+ },
+ "baseHref": {
+ "type": "string",
+ "description": "HTML base HREF to use for the locale (defaults to the locale code)"
+ }
+ },
+ "additionalProperties": false
+ }
+ ]
+ }
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ "target": {
+ "oneOf": [
+ {
+ "$comment": "Extendable target with custom builder",
+ "type": "object",
+ "properties": {
+ "builder": {
+ "type": "string",
+ "description": "The builder used for this package.",
+ "not": {
+ "enum": [
+ "@angular-devkit/build-angular:app-shell",
+ "@angular-devkit/build-angular:browser",
+ "@angular-devkit/build-angular:browser-esbuild",
+ "@angular-devkit/build-angular:dev-server",
+ "@angular-devkit/build-angular:extract-i18n",
+ "@angular-devkit/build-angular:karma",
+ "@angular-devkit/build-angular:protractor",
+ "@angular-devkit/build-angular:server",
+ "@angular-devkit/build-angular:ng-packagr"
+ ]
+ }
+ },
+ "defaultConfiguration": {
+ "type": "string",
+ "description": "A default named configuration to use when a target configuration is not provided."
+ },
+ "options": {
+ "type": "object"
+ },
+ "configurations": {
+ "type": "object",
+ "description": "A map of alternative target options.",
+ "additionalProperties": {
+ "type": "object"
+ }
+ }
+ },
+ "additionalProperties": false,
+ "required": ["builder"]
+ },
+ {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "builder": {
+ "const": "@angular-devkit/build-angular:app-shell"
+ },
+ "defaultConfiguration": {
+ "type": "string",
+ "description": "A default named configuration to use when a target configuration is not provided."
+ },
+ "options": {
+ "$ref": "../../../../angular_devkit/build_angular/src/builders/app-shell/schema.json"
+ },
+ "configurations": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "../../../../angular_devkit/build_angular/src/builders/app-shell/schema.json"
+ }
+ }
+ }
+ },
+ {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "builder": {
+ "const": "@angular-devkit/build-angular:browser"
+ },
+ "defaultConfiguration": {
+ "type": "string",
+ "description": "A default named configuration to use when a target configuration is not provided."
+ },
+ "options": {
+ "$ref": "../../../../angular_devkit/build_angular/src/builders/browser/schema.json"
+ },
+ "configurations": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "../../../../angular_devkit/build_angular/src/builders/browser/schema.json"
+ }
+ }
+ }
+ },
+ {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "builder": {
+ "const": "@angular-devkit/build-angular:browser-esbuild"
+ },
+ "defaultConfiguration": {
+ "type": "string",
+ "description": "A default named configuration to use when a target configuration is not provided."
+ },
+ "options": {
+ "$ref": "../../../../angular_devkit/build_angular/src/builders/browser-esbuild/schema.json"
+ },
+ "configurations": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "../../../../angular_devkit/build_angular/src/builders/browser-esbuild/schema.json"
+ }
+ }
+ }
+ },
+ {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "builder": {
+ "const": "@angular-devkit/build-angular:dev-server"
+ },
+ "defaultConfiguration": {
+ "type": "string",
+ "description": "A default named configuration to use when a target configuration is not provided."
+ },
+ "options": {
+ "$ref": "../../../../angular_devkit/build_angular/src/builders/dev-server/schema.json"
+ },
+ "configurations": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "../../../../angular_devkit/build_angular/src/builders/dev-server/schema.json"
+ }
+ }
+ }
+ },
+ {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "builder": {
+ "const": "@angular-devkit/build-angular:extract-i18n"
+ },
+ "defaultConfiguration": {
+ "type": "string",
+ "description": "A default named configuration to use when a target configuration is not provided."
+ },
+ "options": {
+ "$ref": "../../../../angular_devkit/build_angular/src/builders/extract-i18n/schema.json"
+ },
+ "configurations": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "../../../../angular_devkit/build_angular/src/builders/extract-i18n/schema.json"
+ }
+ }
+ }
+ },
+ {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "builder": {
+ "const": "@angular-devkit/build-angular:karma"
+ },
+ "defaultConfiguration": {
+ "type": "string",
+ "description": "A default named configuration to use when a target configuration is not provided."
+ },
+ "options": {
+ "$ref": "../../../../angular_devkit/build_angular/src/builders/karma/schema.json"
+ },
+ "configurations": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "../../../../angular_devkit/build_angular/src/builders/karma/schema.json"
+ }
+ }
+ }
+ },
+ {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "builder": {
+ "const": "@angular-devkit/build-angular:protractor"
+ },
+ "defaultConfiguration": {
+ "type": "string",
+ "description": "A default named configuration to use when a target configuration is not provided."
+ },
+ "options": {
+ "$ref": "../../../../angular_devkit/build_angular/src/builders/protractor/schema.json"
+ },
+ "configurations": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "../../../../angular_devkit/build_angular/src/builders/protractor/schema.json"
+ }
+ }
+ }
+ },
+ {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "builder": {
+ "const": "@angular-devkit/build-angular:server"
+ },
+ "defaultConfiguration": {
+ "type": "string",
+ "description": "A default named configuration to use when a target configuration is not provided."
+ },
+ "options": {
+ "$ref": "../../../../angular_devkit/build_angular/src/builders/server/schema.json"
+ },
+ "configurations": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "../../../../angular_devkit/build_angular/src/builders/server/schema.json"
+ }
+ }
+ }
+ },
+ {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "builder": {
+ "const": "@angular-devkit/build-angular:ng-packagr"
+ },
+ "defaultConfiguration": {
+ "type": "string",
+ "description": "A default named configuration to use when a target configuration is not provided."
+ },
+ "options": {
+ "$ref": "../../../../angular_devkit/build_angular/src/builders/ng-packagr/schema.json"
+ },
+ "configurations": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "../../../../angular_devkit/build_angular/src/builders/ng-packagr/schema.json"
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+ },
+ "global": {
+ "type": "object",
+ "properties": {
+ "$schema": {
+ "type": "string"
+ },
+ "version": {
+ "$ref": "#/definitions/fileVersion"
+ },
+ "cli": {
+ "$ref": "#/definitions/cliGlobalOptions"
+ },
+ "schematics": {
+ "$ref": "#/definitions/schematicOptions"
+ }
+ },
+ "required": ["version"]
+ }
+ }
+}
diff --git a/src/test/resources/schema_definition_validation/compose_spec.json b/src/test/resources/schema_definition_validation/compose_spec.json
new file mode 100644
index 00000000..b2019660
--- /dev/null
+++ b/src/test/resources/schema_definition_validation/compose_spec.json
@@ -0,0 +1,814 @@
+{
+ "$schema": "http://json-schema.org/draft/2019-09/schema#",
+ "id": "https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json",
+ "type": "object",
+ "title": "Compose Specification",
+ "description": "The Compose file is a YAML file defining a multi-containers based application.",
+
+ "properties": {
+ "version": {
+ "type": "string",
+ "description": "declared for backward compatibility, ignored."
+ },
+
+ "name": {
+ "type": "string",
+ "description": "define the Compose project name, until user defines one explicitly."
+ },
+
+ "services": {
+ "id": "#/properties/services",
+ "type": "object",
+ "patternProperties": {
+ "^[a-zA-Z0-9._-]+$": {
+ "$ref": "#/definitions/service"
+ }
+ },
+ "additionalProperties": false
+ },
+
+ "networks": {
+ "id": "#/properties/networks",
+ "type": "object",
+ "patternProperties": {
+ "^[a-zA-Z0-9._-]+$": {
+ "$ref": "#/definitions/network"
+ }
+ }
+ },
+
+ "volumes": {
+ "id": "#/properties/volumes",
+ "type": "object",
+ "patternProperties": {
+ "^[a-zA-Z0-9._-]+$": {
+ "$ref": "#/definitions/volume"
+ }
+ },
+ "additionalProperties": false
+ },
+
+ "secrets": {
+ "id": "#/properties/secrets",
+ "type": "object",
+ "patternProperties": {
+ "^[a-zA-Z0-9._-]+$": {
+ "$ref": "#/definitions/secret"
+ }
+ },
+ "additionalProperties": false
+ },
+
+ "configs": {
+ "id": "#/properties/configs",
+ "type": "object",
+ "patternProperties": {
+ "^[a-zA-Z0-9._-]+$": {
+ "$ref": "#/definitions/config"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+
+ "patternProperties": {"^x-": {}},
+ "additionalProperties": false,
+
+ "definitions": {
+
+ "service": {
+ "id": "#/definitions/service",
+ "type": "object",
+
+ "properties": {
+ "deploy": {"$ref": "#/definitions/deployment"},
+ "build": {
+ "oneOf": [
+ {"type": "string"},
+ {
+ "type": "object",
+ "properties": {
+ "context": {"type": "string"},
+ "dockerfile": {"type": "string"},
+ "args": {"$ref": "#/definitions/list_or_dict"},
+ "ssh": {"$ref": "#/definitions/list_or_dict"},
+ "labels": {"$ref": "#/definitions/list_or_dict"},
+ "cache_from": {"type": "array", "items": {"type": "string"}},
+ "cache_to": {"type": "array", "items": {"type": "string"}},
+ "no_cache": {"type": "boolean"},
+ "network": {"type": "string"},
+ "pull": {"type": "boolean"},
+ "target": {"type": "string"},
+ "shm_size": {"type": ["integer", "string"]},
+ "extra_hosts": {"$ref": "#/definitions/list_or_dict"},
+ "isolation": {"type": "string"},
+ "secrets": {"$ref": "#/definitions/service_config_or_secret"},
+ "tags":{"type": "array", "items": {"type": "string"}}
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ }
+ ]
+ },
+ "blkio_config": {
+ "type": "object",
+ "properties": {
+ "device_read_bps": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/blkio_limit"}
+ },
+ "device_read_iops": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/blkio_limit"}
+ },
+ "device_write_bps": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/blkio_limit"}
+ },
+ "device_write_iops": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/blkio_limit"}
+ },
+ "weight": {"type": "integer"},
+ "weight_device": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/blkio_weight"}
+ }
+ },
+ "additionalProperties": false
+ },
+ "cap_add": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
+ "cap_drop": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
+ "cgroup_parent": {"type": "string"},
+ "command": {
+ "oneOf": [
+ {"type": "string"},
+ {"type": "array", "items": {"type": "string"}}
+ ]
+ },
+ "configs": {"$ref": "#/definitions/service_config_or_secret"},
+ "container_name": {"type": "string"},
+ "cpu_count": {"type": "integer", "minimum": 0},
+ "cpu_percent": {"type": "integer", "minimum": 0, "maximum": 100},
+ "cpu_shares": {"type": ["number", "string"]},
+ "cpu_quota": {"type": ["number", "string"]},
+ "cpu_period": {"type": ["number", "string"]},
+ "cpu_rt_period": {"type": ["number", "string"]},
+ "cpu_rt_runtime": {"type": ["number", "string"]},
+ "cpus": {"type": ["number", "string"]},
+ "cpuset": {"type": "string"},
+ "credential_spec": {
+ "type": "object",
+ "properties": {
+ "config": {"type": "string"},
+ "file": {"type": "string"},
+ "registry": {"type": "string"}
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ },
+ "depends_on": {
+ "oneOf": [
+ {"$ref": "#/definitions/list_of_strings"},
+ {
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^[a-zA-Z0-9._-]+$": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "condition": {
+ "type": "string",
+ "enum": ["service_started", "service_healthy", "service_completed_successfully"]
+ }
+ },
+ "required": ["condition"]
+ }
+ }
+ }
+ ]
+ },
+ "device_cgroup_rules": {"$ref": "#/definitions/list_of_strings"},
+ "devices": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
+ "dns": {"$ref": "#/definitions/string_or_list"},
+ "dns_opt": {"type": "array","items": {"type": "string"}, "uniqueItems": true},
+ "dns_search": {"$ref": "#/definitions/string_or_list"},
+ "domainname": {"type": "string"},
+ "entrypoint": {
+ "oneOf": [
+ {"type": "string"},
+ {"type": "array", "items": {"type": "string"}}
+ ]
+ },
+ "env_file": {"$ref": "#/definitions/string_or_list"},
+ "environment": {"$ref": "#/definitions/list_or_dict"},
+
+ "expose": {
+ "type": "array",
+ "items": {
+ "type": ["string", "number"],
+ "format": "expose"
+ },
+ "uniqueItems": true
+ },
+ "extends": {
+ "oneOf": [
+ {"type": "string"},
+ {
+ "type": "object",
+
+ "properties": {
+ "service": {"type": "string"},
+ "file": {"type": "string"}
+ },
+ "required": ["service"],
+ "additionalProperties": false
+ }
+ ]
+ },
+ "external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
+ "extra_hosts": {"$ref": "#/definitions/list_or_dict"},
+ "group_add": {
+ "type": "array",
+ "items": {
+ "type": ["string", "number"]
+ },
+ "uniqueItems": true
+ },
+ "healthcheck": {"$ref": "#/definitions/healthcheck"},
+ "hostname": {"type": "string"},
+ "image": {"type": "string"},
+ "init": {"type": "boolean"},
+ "ipc": {"type": "string"},
+ "isolation": {"type": "string"},
+ "labels": {"$ref": "#/definitions/list_or_dict"},
+ "links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
+ "logging": {
+ "type": "object",
+
+ "properties": {
+ "driver": {"type": "string"},
+ "options": {
+ "type": "object",
+ "patternProperties": {
+ "^.+$": {"type": ["string", "number", "null"]}
+ }
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ },
+ "mac_address": {"type": "string"},
+ "mem_limit": {"type": ["number", "string"]},
+ "mem_reservation": {"type": ["string", "integer"]},
+ "mem_swappiness": {"type": "integer"},
+ "memswap_limit": {"type": ["number", "string"]},
+ "network_mode": {"type": "string"},
+ "networks": {
+ "oneOf": [
+ {"$ref": "#/definitions/list_of_strings"},
+ {
+ "type": "object",
+ "patternProperties": {
+ "^[a-zA-Z0-9._-]+$": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "aliases": {"$ref": "#/definitions/list_of_strings"},
+ "ipv4_address": {"type": "string"},
+ "ipv6_address": {"type": "string"},
+ "link_local_ips": {"$ref": "#/definitions/list_of_strings"},
+ "priority": {"type": "number"}
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ },
+ {"type": "null"}
+ ]
+ }
+ },
+ "additionalProperties": false
+ }
+ ]
+ },
+ "oom_kill_disable": {"type": "boolean"},
+ "oom_score_adj": {"type": "integer", "minimum": -1000, "maximum": 1000},
+ "pid": {"type": ["string", "null"]},
+ "pids_limit": {"type": ["number", "string"]},
+ "platform": {"type": "string"},
+ "ports": {
+ "type": "array",
+ "items": {
+ "oneOf": [
+ {"type": "number", "format": "ports"},
+ {"type": "string", "format": "ports"},
+ {
+ "type": "object",
+ "properties": {
+ "mode": {"type": "string"},
+ "host_ip": {"type": "string"},
+ "target": {"type": "integer"},
+ "published": {"type": ["string", "integer"]},
+ "protocol": {"type": "string"}
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ }
+ ]
+ },
+ "uniqueItems": true
+ },
+ "privileged": {"type": "boolean"},
+ "profiles": {"$ref": "#/definitions/list_of_strings"},
+ "pull_policy": {"type": "string", "enum": [
+ "always", "never", "if_not_present", "build", "missing"
+ ]},
+ "read_only": {"type": "boolean"},
+ "restart": {"type": "string"},
+ "runtime": {
+ "type": "string"
+ },
+ "scale": {
+ "type": "integer"
+ },
+ "security_opt": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
+ "shm_size": {"type": ["number", "string"]},
+ "secrets": {"$ref": "#/definitions/service_config_or_secret"},
+ "sysctls": {"$ref": "#/definitions/list_or_dict"},
+ "stdin_open": {"type": "boolean"},
+ "stop_grace_period": {"type": "string", "format": "duration"},
+ "stop_signal": {"type": "string"},
+ "storage_opt": {"type": "object"},
+ "tmpfs": {"$ref": "#/definitions/string_or_list"},
+ "tty": {"type": "boolean"},
+ "ulimits": {
+ "type": "object",
+ "patternProperties": {
+ "^[a-z]+$": {
+ "oneOf": [
+ {"type": "integer"},
+ {
+ "type": "object",
+ "properties": {
+ "hard": {"type": "integer"},
+ "soft": {"type": "integer"}
+ },
+ "required": ["soft", "hard"],
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ }
+ ]
+ }
+ }
+ },
+ "user": {"type": "string"},
+ "userns_mode": {"type": "string"},
+ "volumes": {
+ "type": "array",
+ "items": {
+ "oneOf": [
+ {"type": "string"},
+ {
+ "type": "object",
+ "required": ["type"],
+ "properties": {
+ "type": {"type": "string"},
+ "source": {"type": "string"},
+ "target": {"type": "string"},
+ "read_only": {"type": "boolean"},
+ "consistency": {"type": "string"},
+ "bind": {
+ "type": "object",
+ "properties": {
+ "propagation": {"type": "string"},
+ "create_host_path": {"type": "boolean"},
+ "selinux": {"type": "string", "enum": ["z", "Z"]}
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ },
+ "volume": {
+ "type": "object",
+ "properties": {
+ "nocopy": {"type": "boolean"}
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ },
+ "tmpfs": {
+ "type": "object",
+ "properties": {
+ "size": {
+ "oneOf": [
+ {"type": "integer", "minimum": 0},
+ {"type": "string"}
+ ]
+ },
+ "mode": {"type": "number"}
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ }
+ ]
+ },
+ "uniqueItems": true
+ },
+ "volumes_from": {
+ "type": "array",
+ "items": {"type": "string"},
+ "uniqueItems": true
+ },
+ "working_dir": {"type": "string"}
+ },
+ "patternProperties": {"^x-": {}},
+ "additionalProperties": false
+ },
+
+ "healthcheck": {
+ "id": "#/definitions/healthcheck",
+ "type": "object",
+ "properties": {
+ "disable": {"type": "boolean"},
+ "interval": {"type": "string", "format": "duration"},
+ "retries": {"type": "number"},
+ "test": {
+ "oneOf": [
+ {"type": "string"},
+ {"type": "array", "items": {"type": "string"}}
+ ]
+ },
+ "timeout": {"type": "string", "format": "duration"},
+ "start_period": {"type": "string", "format": "duration"}
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ },
+ "deployment": {
+ "id": "#/definitions/deployment",
+ "type": ["object", "null"],
+ "properties": {
+ "mode": {"type": "string"},
+ "endpoint_mode": {"type": "string"},
+ "replicas": {"type": "integer"},
+ "labels": {"$ref": "#/definitions/list_or_dict"},
+ "rollback_config": {
+ "type": "object",
+ "properties": {
+ "parallelism": {"type": "integer"},
+ "delay": {"type": "string", "format": "duration"},
+ "failure_action": {"type": "string"},
+ "monitor": {"type": "string", "format": "duration"},
+ "max_failure_ratio": {"type": "number"},
+ "order": {"type": "string", "enum": [
+ "start-first", "stop-first"
+ ]}
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ },
+ "update_config": {
+ "type": "object",
+ "properties": {
+ "parallelism": {"type": "integer"},
+ "delay": {"type": "string", "format": "duration"},
+ "failure_action": {"type": "string"},
+ "monitor": {"type": "string", "format": "duration"},
+ "max_failure_ratio": {"type": "number"},
+ "order": {"type": "string", "enum": [
+ "start-first", "stop-first"
+ ]}
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ },
+ "resources": {
+ "type": "object",
+ "properties": {
+ "limits": {
+ "type": "object",
+ "properties": {
+ "cpus": {"type": ["number", "string"]},
+ "memory": {"type": "string"},
+ "pids": {"type": "integer"}
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ },
+ "reservations": {
+ "type": "object",
+ "properties": {
+ "cpus": {"type": ["number", "string"]},
+ "memory": {"type": "string"},
+ "generic_resources": {"$ref": "#/definitions/generic_resources"},
+ "devices": {"$ref": "#/definitions/devices"}
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ },
+ "restart_policy": {
+ "type": "object",
+ "properties": {
+ "condition": {"type": "string"},
+ "delay": {"type": "string", "format": "duration"},
+ "max_attempts": {"type": "integer"},
+ "window": {"type": "string", "format": "duration"}
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ },
+ "placement": {
+ "type": "object",
+ "properties": {
+ "constraints": {"type": "array", "items": {"type": "string"}},
+ "preferences": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "spread": {"type": "string"}
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ }
+ },
+ "max_replicas_per_node": {"type": "integer"}
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ },
+
+ "generic_resources": {
+ "id": "#/definitions/generic_resources",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "discrete_resource_spec": {
+ "type": "object",
+ "properties": {
+ "kind": {"type": "string"},
+ "value": {"type": "number"}
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ }
+ },
+
+ "devices": {
+ "id": "#/definitions/devices",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "capabilities": {"$ref": "#/definitions/list_of_strings"},
+ "count": {"type": ["string", "integer"]},
+ "device_ids": {"$ref": "#/definitions/list_of_strings"},
+ "driver":{"type": "string"},
+ "options":{"$ref": "#/definitions/list_or_dict"}
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ }
+ },
+
+ "network": {
+ "id": "#/definitions/network",
+ "type": ["object", "null"],
+ "properties": {
+ "name": {"type": "string"},
+ "driver": {"type": "string"},
+ "driver_opts": {
+ "type": "object",
+ "patternProperties": {
+ "^.+$": {"type": ["string", "number"]}
+ }
+ },
+ "ipam": {
+ "type": "object",
+ "properties": {
+ "driver": {"type": "string"},
+ "config": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "subnet": {"type": "string", "format": "subnet_ip_address"},
+ "ip_range": {"type": "string"},
+ "gateway": {"type": "string"},
+ "aux_addresses": {
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {"^.+$": {"type": "string"}}
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ }
+ },
+ "options": {
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {"^.+$": {"type": "string"}}
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ },
+ "external": {
+ "type": ["boolean", "object"],
+ "properties": {
+ "name": {
+ "deprecated": true,
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ },
+ "internal": {"type": "boolean"},
+ "enable_ipv6": {"type": "boolean"},
+ "attachable": {"type": "boolean"},
+ "labels": {"$ref": "#/definitions/list_or_dict"}
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ },
+
+ "volume": {
+ "id": "#/definitions/volume",
+ "type": ["object", "null"],
+ "properties": {
+ "name": {"type": "string"},
+ "driver": {"type": "string"},
+ "driver_opts": {
+ "type": "object",
+ "patternProperties": {
+ "^.+$": {"type": ["string", "number"]}
+ }
+ },
+ "external": {
+ "type": ["boolean", "object"],
+ "properties": {
+ "name": {
+ "deprecated": true,
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ },
+ "labels": {"$ref": "#/definitions/list_or_dict"}
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ },
+
+ "secret": {
+ "id": "#/definitions/secret",
+ "type": "object",
+ "properties": {
+ "name": {"type": "string"},
+ "environment": {"type": "string"},
+ "file": {"type": "string"},
+ "external": {
+ "type": ["boolean", "object"],
+ "properties": {
+ "name": {"type": "string"}
+ }
+ },
+ "labels": {"$ref": "#/definitions/list_or_dict"},
+ "driver": {"type": "string"},
+ "driver_opts": {
+ "type": "object",
+ "patternProperties": {
+ "^.+$": {"type": ["string", "number"]}
+ }
+ },
+ "template_driver": {"type": "string"}
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ },
+
+ "config": {
+ "id": "#/definitions/config",
+ "type": "object",
+ "properties": {
+ "name": {"type": "string"},
+ "file": {"type": "string"},
+ "external": {
+ "type": ["boolean", "object"],
+ "properties": {
+ "name": {
+ "deprecated": true,
+ "type": "string"
+ }
+ }
+ },
+ "labels": {"$ref": "#/definitions/list_or_dict"},
+ "template_driver": {"type": "string"}
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ },
+
+ "string_or_list": {
+ "oneOf": [
+ {"type": "string"},
+ {"$ref": "#/definitions/list_of_strings"}
+ ]
+ },
+
+ "list_of_strings": {
+ "type": "array",
+ "items": {"type": "string"},
+ "uniqueItems": true
+ },
+
+ "list_or_dict": {
+ "oneOf": [
+ {
+ "type": "object",
+ "patternProperties": {
+ ".+": {
+ "type": ["string", "number", "boolean", "null"]
+ }
+ },
+ "additionalProperties": false
+ },
+ {"type": "array", "items": {"type": "string"}, "uniqueItems": true}
+ ]
+ },
+
+ "blkio_limit": {
+ "type": "object",
+ "properties": {
+ "path": {"type": "string"},
+ "rate": {"type": ["integer", "string"]}
+ },
+ "additionalProperties": false
+ },
+ "blkio_weight": {
+ "type": "object",
+ "properties": {
+ "path": {"type": "string"},
+ "weight": {"type": "integer"}
+ },
+ "additionalProperties": false
+ },
+
+ "service_config_or_secret": {
+ "type": "array",
+ "items": {
+ "oneOf": [
+ {"type": "string"},
+ {
+ "type": "object",
+ "properties": {
+ "source": {"type": "string"},
+ "target": {"type": "string"},
+ "uid": {"type": "string"},
+ "gid": {"type": "string"},
+ "mode": {"type": "number"}
+ },
+ "additionalProperties": false,
+ "patternProperties": {"^x-": {}}
+ }
+ ]
+ }
+ },
+
+ "constraints": {
+ "service": {
+ "id": "#/definitions/constraints/service",
+ "anyOf": [
+ {"required": ["build"]},
+ {"required": ["image"]}
+ ],
+ "properties": {
+ "build": {
+ "required": ["context"]
+ }
+ }
+ }
+ }
+ }
+}