diff --git a/package.json b/package.json index e93a3febb..d99759294 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "lint": "yarn prelint && yarn lint.prettier && yarn lint.eslint", "lint.fix": "yarn lint.prettier --write && yarn lint.eslint --fix", "lint.eslint": "eslint --cache --cache-location .cache/.eslintcache --ext=.js,.mjs,.ts packages test-harness", - "lint.prettier": "prettier --ignore-path .eslintignore --ignore-unknown --check packages/core/src/ruleset/meta/*.json packages/rulesets/src/{asyncapi,oas}/schemas/*.json docs/**/*.md README.md", + "lint.prettier": "prettier --ignore-path .eslintignore --ignore-unknown --check packages/core/src/ruleset/meta/*.json packages/rulesets/src/{asyncapi,oas}/schemas/**/*.json docs/**/*.md README.md", "pretest": "yarn workspaces foreach run pretest", "test": "yarn pretest && yarn test.karma && yarn test.jest", "pretest.harness": "ts-node -T test-harness/scripts/generate-tests.ts", @@ -138,7 +138,7 @@ "packages/core/src/ruleset/meta/*.json": [ "prettier --ignore-path .eslintignore --write" ], - "packages/rulesets/src/{asyncapi,oas}/schemas/*.json": [ + "packages/rulesets/src/{asyncapi,oas}/schemas/**/*.json": [ "prettier --ignore-path .eslintignore --write" ] }, diff --git a/packages/rulesets/package.json b/packages/rulesets/package.json index 8f8483227..47ea02b23 100644 --- a/packages/rulesets/package.json +++ b/packages/rulesets/package.json @@ -53,6 +53,7 @@ "@stoplight/path": "^1.3.2", "@stoplight/spectral-parsers": "*", "@stoplight/spectral-ref-resolver": "*", + "ajv-merge-patch": "^5.0.1", "gzip-size": "^6.0.0", "immer": "^9.0.6", "terser": "^5.26.0" diff --git a/packages/rulesets/scripts/compile-schemas.ts b/packages/rulesets/scripts/compile-schemas.ts index 5c4169e57..7378ed7c7 100644 --- a/packages/rulesets/scripts/compile-schemas.ts +++ b/packages/rulesets/scripts/compile-schemas.ts @@ -13,7 +13,9 @@ import { sync } from 'gzip-size'; const cwd = path.join(__dirname, '../src'); const schemas = [ - 'oas/schemas/json-schema-draft-04.json', + 'oas/schemas/json-schema/draft-04.json', + 'oas/schemas/json-schema/draft-2020-12/index.json', + 'oas/schemas/json-schema/draft-2020-12/validation.json', 'oas/schemas/oas/v2.0.json', 'oas/schemas/oas/v3.0.json', 'oas/schemas/oas/v3.1/dialect.schema.json', diff --git a/packages/rulesets/src/oas/__tests__/oas3-schema.test.ts b/packages/rulesets/src/oas/__tests__/oas3-schema.test.ts index cfbbe68dc..67a2024be 100644 --- a/packages/rulesets/src/oas/__tests__/oas3-schema.test.ts +++ b/packages/rulesets/src/oas/__tests__/oas3-schema.test.ts @@ -150,52 +150,6 @@ testRule('oas3-schema', [ ], }, - { - name: 'oas3.1: paths is not required', - document: { - openapi: '3.1.0', - info: { - title: 'Example jsonSchemaDialect error', - version: '1.0.0', - }, - webhooks: {}, - }, - errors: [], - }, - - { - name: 'oas3.1: uri template as server url', - document: { - openapi: '3.1.0', - info: { - title: 'Server URL may have variables', - version: '1.0.0', - }, - webhooks: {}, - // https://spec.openapis.org/oas/v3.1.0#server-object-example - servers: [ - { - url: 'https://{username}.gigantic-server.com:{port}/{basePath}', - description: 'The production API server', - variables: { - username: { - default: 'demo', - description: 'this value is assigned by the service provider, in this example `gigantic-server.com`', - }, - port: { - enum: ['8443', '443'], - default: '8443', - }, - basePath: { - default: 'v2', - }, - }, - }, - ], - }, - errors: [], - }, - { name: 'oas3.0: validate parameters', document: { @@ -319,6 +273,7 @@ testRule('oas3-schema', [ }, ], }, + { name: 'oas3.0: validate responses', document: { @@ -383,4 +338,246 @@ testRule('oas3-schema', [ }, ], }, + + { + name: 'oas3.0: validate schemas', + document: { + openapi: '3.0.3', + info: { + title: 'our-api', + version: '1.0', + }, + paths: { + '/config': { + parameters: [ + { + schema: null, + name: 'id', + in: 'query', + required: false, + description: 'Id of an existing config.', + }, + ], + get: { + summary: 'Get User Info by User ID', + operationId: 'get-users-settings', + responses: { + '200': { + description: 'Settings for User Found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + key: { + type: 'string,', + }, + value: { + type: 'string', + }, + }, + required: ['key', 'value'], + }, + }, + }, + }, + }, + }, + }, + }, + components: { + schemas: { + Schema: { + type: 'object', + additionalProperties: { + type: 'int', + }, + }, + Schema_2: { + type: 'object', + additionalProperties: 'invalid', + }, + }, + }, + }, + errors: [ + { + message: '"schema" property must be object.', + path: ['paths', '/config', 'parameters', '0', 'schema'], + severity: DiagnosticSeverity.Error, + }, + { + message: + '"type" property must be equal to one of the allowed values: "array", "boolean", "integer", "number", "object", "string". Did you mean "string"?.', + path: [ + 'paths', + '/config', + 'get', + 'responses', + '200', + 'content', + 'application/json', + 'schema', + 'properties', + 'key', + 'type', + ], + }, + { + message: + '"type" property must be equal to one of the allowed values: "array", "boolean", "integer", "number", "object", "string". Did you mean "integer"?.', + path: ['components', 'schemas', 'Schema', 'additionalProperties', 'type'], + severity: DiagnosticSeverity.Error, + }, + { + message: '"additionalProperties" property must be a valid Schema Object.', + path: ['components', 'schemas', 'Schema_2', 'additionalProperties'], + severity: DiagnosticSeverity.Error, + }, + ], + }, + + { + name: 'oas3.1: paths is not required', + document: { + openapi: '3.1.0', + info: { + title: 'Example jsonSchemaDialect error', + version: '1.0.0', + }, + webhooks: {}, + }, + errors: [], + }, + + { + name: 'oas3.1: validate schemas', + document: { + openapi: '3.1.0', + info: { + title: 'our-api', + version: '1.0', + }, + paths: { + '/config': { + parameters: [ + { + schema: null, + name: 'id', + in: 'query', + required: false, + description: 'Id of an existing config.', + }, + ], + get: { + summary: 'Get User Info by User ID', + operationId: 'get-users-settings', + responses: { + '200': { + description: 'Settings for User Found', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + key: { + type: 'string,', + }, + value: { + type: 'string', + }, + }, + required: ['key', 'value'], + }, + }, + }, + }, + }, + }, + }, + }, + components: { + schemas: { + Schema: { + type: 'object', + additionalProperties: { + type: 'int', + }, + }, + Schema_2: { + type: 'object', + additionalProperties: 'invalid', + }, + }, + }, + }, + errors: [ + { + message: '"schema" property must be a valid Schema Object.', + path: ['paths', '/config', 'parameters', '0', 'schema'], + severity: DiagnosticSeverity.Error, + }, + { + message: + '"type" property must be equal to one of the allowed values: "array", "boolean", "integer", "null", "number", "object", "string". Did you mean "string"?.', + path: [ + 'paths', + '/config', + 'get', + 'responses', + '200', + 'content', + 'application/json', + 'schema', + 'properties', + 'key', + 'type', + ], + }, + { + message: + '"type" property must be equal to one of the allowed values: "array", "boolean", "integer", "null", "number", "object", "string". Did you mean "integer"?.', + path: ['components', 'schemas', 'Schema', 'additionalProperties', 'type'], + severity: DiagnosticSeverity.Error, + }, + { + message: '"additionalProperties" property must be a valid Schema Object.', + path: ['components', 'schemas', 'Schema_2', 'additionalProperties'], + severity: DiagnosticSeverity.Error, + }, + ], + }, + + { + name: 'oas3.1: uri template as server url', + document: { + openapi: '3.1.0', + info: { + title: 'Server URL may have variables', + version: '1.0.0', + }, + webhooks: {}, + // https://spec.openapis.org/oas/v3.1.0#server-object-example + servers: [ + { + url: 'https://{username}.gigantic-server.com:{port}/{basePath}', + description: 'The production API server', + variables: { + username: { + default: 'demo', + description: 'this value is assigned by the service provider, in this example `gigantic-server.com`', + }, + port: { + enum: ['8443', '443'], + default: '8443', + }, + basePath: { + default: 'v2', + }, + }, + }, + ], + }, + errors: [], + }, ]); diff --git a/packages/rulesets/src/oas/functions/oasDocumentSchema.ts b/packages/rulesets/src/oas/functions/oasDocumentSchema.ts index cf349ad39..15cda8a4d 100644 --- a/packages/rulesets/src/oas/functions/oasDocumentSchema.ts +++ b/packages/rulesets/src/oas/functions/oasDocumentSchema.ts @@ -16,17 +16,14 @@ export default createRulesetFunction( const formats = context.document.formats; if (formats === null || formats === void 0) return; - const validator = formats.has(oas2) - ? validators.oas2_0 - : formats.has(oas3_1) - ? validators.oas3_1 - : validators.oas3_0; + const schema = formats.has(oas2) ? 'oas2_0' : formats.has(oas3_1) ? 'oas3_1' : 'oas3_0'; + const validator = validators[schema]; validator(input); - const errors = validator['errors'] as ErrorObject[] | undefined; + const errors = validator['errors'] as ErrorObject[] | null; - return errors?.filter(isRelevantError).map(e => processError(input, e)); + return errors?.reduce((errors, e) => processError(errors, input, schema, e), []); }, ); @@ -34,19 +31,27 @@ function isRelevantError(error: ErrorObject): boolean { return error.keyword !== 'if'; } -function processError(input: unknown, error: ErrorObject): IFunctionResult { +function processError( + errors: IFunctionResult[], + input: unknown, + schema: 'oas2_0' | 'oas3_0' | 'oas3_1', + error: ErrorObject, +): IFunctionResult[] { + if (!isRelevantError(error)) { + return errors; + } + const path = error.instancePath === '' ? [] : error.instancePath.slice(1).split('/'); const property = path.length === 0 ? null : path[path.length - 1]; + let message: string; + switch (error.keyword) { case 'additionalProperties': { const additionalProperty = error.params['additionalProperty'] as string; path.push(additionalProperty); - - return { - message: `Property "${additionalProperty}" is not expected to be here`, - path, - }; + message = `Property "${additionalProperty}" is not expected to be here`; + break; } case 'enum': { @@ -71,24 +76,24 @@ function processError(input: unknown, error: ErrorObject): IFunctionResult { } } - return { - message: `${cleanAjvMessage(property, error.message)}: ${printedValues}${suggestion}`, - path, - }; + message = `${cleanAjvMessage(property, error.message)}: ${printedValues}${suggestion}`; + break; } case 'errorMessage': - return { - message: String(error.message), - path, - }; + message = String(error.message); + break; default: - return { - message: cleanAjvMessage(property, error.message), - path, - }; + message = cleanAjvMessage(property, error.message); } + + errors.push({ + message, + path, + }); + + return errors; } function findBestMatch(value: string, allowedValues: unknown[]): string | null { diff --git a/packages/rulesets/src/oas/schemas/json-schema/LICENSE b/packages/rulesets/src/oas/schemas/json-schema/LICENSE new file mode 100644 index 000000000..397909a84 --- /dev/null +++ b/packages/rulesets/src/oas/schemas/json-schema/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015-2021 Evgeny Poberezkin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/rulesets/src/oas/schemas/json-schema/README.md b/packages/rulesets/src/oas/schemas/json-schema/README.md new file mode 100644 index 000000000..9e0198fdf --- /dev/null +++ b/packages/rulesets/src/oas/schemas/json-schema/README.md @@ -0,0 +1,2 @@ +The schemas here are based on https://github.com/ajv-validator/ajv with one change related to the validation of the "type" property to yield more useful validation results. +draft-04 is based on https://github.com/ajv-validator/ajv-draft-04 diff --git a/packages/rulesets/src/oas/schemas/json-schema-draft-04.json b/packages/rulesets/src/oas/schemas/json-schema/draft-04.json similarity index 100% rename from packages/rulesets/src/oas/schemas/json-schema-draft-04.json rename to packages/rulesets/src/oas/schemas/json-schema/draft-04.json diff --git a/packages/rulesets/src/oas/schemas/json-schema/draft-2020-12/index.json b/packages/rulesets/src/oas/schemas/json-schema/draft-2020-12/index.json new file mode 100644 index 000000000..fc4b1b5b4 --- /dev/null +++ b/packages/rulesets/src/oas/schemas/json-schema/draft-2020-12/index.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://stoplight.io/json-schema/draft/2020-12", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/core": true, + "https://json-schema.org/draft/2020-12/vocab/applicator": true, + "https://json-schema.org/draft/2020-12/vocab/unevaluated": true, + "https://json-schema.org/draft/2020-12/vocab/validation": true, + "https://json-schema.org/draft/2020-12/vocab/meta-data": true, + "https://json-schema.org/draft/2020-12/vocab/format-annotation": true, + "https://json-schema.org/draft/2020-12/vocab/content": true + }, + "$dynamicAnchor": "meta", + + "title": "Core and Validation specifications meta-schema", + + "if": { + "type": "object" + }, + "then": { + "allOf": [ + { "$ref": "https://json-schema.org/draft/2020-12/meta/core" }, + { "$ref": "https://json-schema.org/draft/2020-12/meta/applicator" }, + { "$ref": "https://json-schema.org/draft/2020-12/meta/unevaluated" }, + { "$ref": "https://stoplight.io/json-schema/draft/2020-12/meta/validation" }, + { "$ref": "https://json-schema.org/draft/2020-12/meta/meta-data" }, + { "$ref": "https://json-schema.org/draft/2020-12/meta/format-annotation" }, + { "$ref": "https://json-schema.org/draft/2020-12/meta/content" } + ], + "properties": { + "definitions": { + "$ref": "https://json-schema.org/draft/2020-12/schema#/properties/definitions" + }, + "dependencies": { + "$ref": "https://json-schema.org/draft/2020-12/schema#/properties/dependencies" + }, + "$recursiveAnchor": { + "$ref": "https://json-schema.org/draft/2020-12/schema#/properties/%24recursiveAnchor" + }, + "$recursiveRef": { + "$ref": "https://json-schema.org/draft/2020-12/schema#/properties/%24recursiveRef" + } + } + }, + "else": { + "if": { + "type": "boolean" + }, + "then": true, + "else": { + "not": true, + "errorMessage": "\"{{property}}\" property must be a valid Schema Object" + } + }, + "$comment": "This meta-schema also defines keywords that have appeared in previous drafts in order to prevent incompatible extensions as they remain in common use." +} diff --git a/packages/rulesets/src/oas/schemas/json-schema/draft-2020-12/validation.json b/packages/rulesets/src/oas/schemas/json-schema/draft-2020-12/validation.json new file mode 100644 index 000000000..29c4e927e --- /dev/null +++ b/packages/rulesets/src/oas/schemas/json-schema/draft-2020-12/validation.json @@ -0,0 +1,102 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://stoplight.io/json-schema/draft/2020-12/meta/validation", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/validation": true + }, + "$dynamicAnchor": "meta", + + "title": "Validation vocabulary meta-schema", + "type": ["object", "boolean"], + "properties": { + "type": { + "if": { + "type": "string" + }, + "then": { + "$ref": "#/$defs/simpleTypes" + }, + "else": { + "if": { + "type": "array" + }, + "then": { + "type": "array", + "items": { "$ref": "#/$defs/simpleTypes" }, + "minItems": 1, + "uniqueItems": true + }, + "else": { + "not": true, + "errorMessage": "\"type\" property must be either a string or an array of strings" + } + } + }, + "const": true, + "enum": { + "type": "array", + "items": true + }, + "multipleOf": { + "type": "number", + "exclusiveMinimum": 0 + }, + "maximum": { + "type": "number" + }, + "exclusiveMaximum": { + "type": "number" + }, + "minimum": { + "type": "number" + }, + "exclusiveMinimum": { + "type": "number" + }, + "maxLength": { "$ref": "#/$defs/nonNegativeInteger" }, + "minLength": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, + "pattern": { + "type": "string", + "format": "regex" + }, + "maxItems": { "$ref": "#/$defs/nonNegativeInteger" }, + "minItems": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, + "uniqueItems": { + "type": "boolean", + "default": false + }, + "maxContains": { "$ref": "#/$defs/nonNegativeInteger" }, + "minContains": { + "$ref": "#/$defs/nonNegativeInteger", + "default": 1 + }, + "maxProperties": { "$ref": "#/$defs/nonNegativeInteger" }, + "minProperties": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, + "required": { "$ref": "#/$defs/stringArray" }, + "dependentRequired": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/stringArray" + } + } + }, + "$defs": { + "nonNegativeInteger": { + "type": "integer", + "minimum": 0 + }, + "nonNegativeIntegerDefault0": { + "$ref": "#/$defs/nonNegativeInteger", + "default": 0 + }, + "simpleTypes": { + "enum": ["array", "boolean", "integer", "null", "number", "object", "string"] + }, + "stringArray": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true, + "default": [] + } + } +} diff --git a/packages/rulesets/src/oas/schemas/oas/v2.0.json b/packages/rulesets/src/oas/schemas/oas/v2.0.json index 3c0c73047..4eee714a3 100644 --- a/packages/rulesets/src/oas/schemas/oas/v2.0.json +++ b/packages/rulesets/src/oas/schemas/oas/v2.0.json @@ -350,14 +350,16 @@ } }, "responseValue": { - "oneOf": [ - { - "$ref": "#/definitions/response" - }, - { - "$ref": "#/definitions/jsonReference" - } - ] + "if": { + "type": "object", + "required": ["$ref"] + }, + "then": { + "$ref": "#/definitions/jsonReference" + }, + "else": { + "$ref": "#/definitions/response" + } }, "response": { "type": "object", @@ -930,14 +932,22 @@ "$ref": "http://json-schema.org/draft-04/schema#/properties/enum" }, "additionalProperties": { - "anyOf": [ - { - "$ref": "#/definitions/schema" - }, - { + "if": { + "type": "object" + }, + "then": { + "$ref": "#/definitions/schema" + }, + "else": { + "if": { "type": "boolean" + }, + "then": true, + "else": { + "not": true, + "errorMessage": "\"additionalProperties\" property must be a valid schema" } - ], + }, "default": {} }, "type": { @@ -1379,14 +1389,16 @@ "description": "The parameters needed to send a valid API call.", "additionalItems": false, "items": { - "oneOf": [ - { - "$ref": "#/definitions/parameter" - }, - { - "$ref": "#/definitions/jsonReference" - } - ] + "if": { + "type": "object", + "required": ["$ref"] + }, + "then": { + "$ref": "#/definitions/jsonReference" + }, + "else": { + "$ref": "#/definitions/parameter" + } }, "uniqueItems": true }, diff --git a/packages/rulesets/src/oas/schemas/oas/v3.0.json b/packages/rulesets/src/oas/schemas/oas/v3.0.json index 867ee6e48..ff86a3c8f 100644 --- a/packages/rulesets/src/oas/schemas/oas/v3.0.json +++ b/packages/rulesets/src/oas/schemas/oas/v3.0.json @@ -497,14 +497,22 @@ "$ref": "#/definitions/Reference" }, "else": { - "oneOf": [ - { - "$ref": "#/definitions/Schema" - }, - { + "if": { + "type": "object" + }, + "then": { + "$ref": "#/definitions/Schema" + }, + "else": { + "if": { "type": "boolean" + }, + "then": true, + "else": { + "not": true, + "errorMessage": "\"additionalProperties\" property must be a valid Schema Object" } - ] + } }, "default": true }, diff --git a/packages/rulesets/src/oas/schemas/oas/v3.1/dialect.schema.json b/packages/rulesets/src/oas/schemas/oas/v3.1/dialect.schema.json index 3b2064572..53a56900a 100644 --- a/packages/rulesets/src/oas/schemas/oas/v3.1/dialect.schema.json +++ b/packages/rulesets/src/oas/schemas/oas/v3.1/dialect.schema.json @@ -16,10 +16,23 @@ "https://spec.openapis.org/oas/3.1/vocab/base": false }, - "$dynamicAnchor": "meta", - - "allOf": [ - { "$ref": "https://json-schema.org/draft/2020-12/schema" }, - { "$ref": "https://spec.openapis.org/oas/3.1/meta/base" } - ] + "if": { + "type": "object" + }, + "then": { + "allOf": [ + { "$ref": "https://stoplight.io/json-schema/draft/2020-12" }, + { "$ref": "https://spec.openapis.org/oas/3.1/meta/base" } + ] + }, + "else": { + "if": { + "type": "boolean" + }, + "then": true, + "else": { + "not": true, + "errorMessage": "\"{{property}}\" property must be a valid Schema Object" + } + } } diff --git a/packages/rulesets/src/oas/schemas/oas/v3.1/index.json b/packages/rulesets/src/oas/schemas/oas/v3.1/index.json index 51b7c14de..128e844fd 100644 --- a/packages/rulesets/src/oas/schemas/oas/v3.1/index.json +++ b/packages/rulesets/src/oas/schemas/oas/v3.1/index.json @@ -967,8 +967,7 @@ }, "schema": { "$comment": "https://spec.openapis.org/oas/v3.1.0#schema-object", - "$dynamicAnchor": "meta", - "type": ["object", "boolean"] + "$ref": "https://spec.openapis.org/oas/3.1/dialect/base" }, "security-scheme": { "$comment": "https://spec.openapis.org/oas/v3.1.0#security-scheme-object", diff --git a/packages/rulesets/src/oas/schemas/oas/v3.1/meta.schema.json b/packages/rulesets/src/oas/schemas/oas/v3.1/meta.schema.json index e8a20ef48..ca4f2b03f 100644 --- a/packages/rulesets/src/oas/schemas/oas/v3.1/meta.schema.json +++ b/packages/rulesets/src/oas/schemas/oas/v3.1/meta.schema.json @@ -9,16 +9,28 @@ "https://spec.openapis.org/oas/3.1/vocab/base": true }, - "$dynamicAnchor": "meta", - - "type": ["object", "boolean"], - "properties": { - "example": true, - "discriminator": { "$ref": "#/$defs/discriminator" }, - "externalDocs": { "$ref": "#/$defs/external-docs" }, - "xml": { "$ref": "#/$defs/xml" } + "if": { + "type": "object" + }, + "then": { + "type": "object", + "properties": { + "example": true, + "discriminator": { "$ref": "#/$defs/discriminator" }, + "externalDocs": { "$ref": "#/$defs/external-docs" }, + "xml": { "$ref": "#/$defs/xml" } + } + }, + "else": { + "if": { + "type": "boolean" + }, + "then": true, + "else": { + "not": true, + "errorMessage": "\"{{property}}\" property must be a valid Schema Object" + } }, - "$defs": { "extensible": { "patternProperties": { diff --git a/yarn.lock b/yarn.lock index f2fb6dfc8..387160e49 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2850,6 +2850,7 @@ __metadata: "@types/json-schema": ^7.0.7 ajv: ^8.12.0 ajv-formats: ~2.1.0 + ajv-merge-patch: ^5.0.1 gzip-size: ^6.0.0 immer: ^9.0.6 json-schema-traverse: ^1.0.0 @@ -3723,6 +3724,18 @@ __metadata: languageName: node linkType: hard +"ajv-merge-patch@npm:^5.0.1": + version: 5.0.1 + resolution: "ajv-merge-patch@npm:5.0.1" + dependencies: + fast-json-patch: ^2.0.6 + json-merge-patch: ^1.0.2 + peerDependencies: + ajv: ">=8.0.0" + checksum: 1f9354c26fe7af840d50fbd83b29ab65f3edeeb9f75c1257a42a89ee67526b49fa3232e5989ceb30090e38caf6e437d65623e5cef0a538a36e3d872c03e0ec4e + languageName: node + linkType: hard + "ajv@npm:^6.10.0, ajv@npm:^6.12.4": version: 6.12.6 resolution: "ajv@npm:6.12.6" @@ -6293,6 +6306,13 @@ __metadata: languageName: node linkType: hard +"fast-deep-equal@npm:^2.0.1": + version: 2.0.1 + resolution: "fast-deep-equal@npm:2.0.1" + checksum: b701835a87985e0ec4925bdf1f0c1e7eb56309b5d12d534d5b4b69d95a54d65bb16861c081781ead55f73f12d6c60ba668713391ee7fbf6b0567026f579b7b0b + languageName: node + linkType: hard + "fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" @@ -6320,6 +6340,15 @@ __metadata: languageName: node linkType: hard +"fast-json-patch@npm:^2.0.6": + version: 2.2.1 + resolution: "fast-json-patch@npm:2.2.1" + dependencies: + fast-deep-equal: ^2.0.1 + checksum: 955aebb3f873d1fb0452a5d8c34865ce4c3c6cdafeb7d3ad98d43b467de9a5a0d304132f8595fd2b373f8f4d200605947e865286b180f3a55e8377a634893164 + languageName: node + linkType: hard + "fast-json-stable-stringify@npm:2.x, fast-json-stable-stringify@npm:^2.0.0": version: 2.0.0 resolution: "fast-json-stable-stringify@npm:2.0.0" @@ -8415,6 +8444,15 @@ __metadata: languageName: node linkType: hard +"json-merge-patch@npm:^1.0.2": + version: 1.0.2 + resolution: "json-merge-patch@npm:1.0.2" + dependencies: + fast-deep-equal: ^3.1.3 + checksum: 06867dbb93c9c3a698fba8a89f5ec1bd7a19697667a97d084d893c3ecd9ccecac07f251a531ffdf0c80df042ef3f33b5f67cdd7d73933c9cf7d9ebeaf1be24f5 + languageName: node + linkType: hard + "json-parse-better-errors@npm:^1.0.1": version: 1.0.2 resolution: "json-parse-better-errors@npm:1.0.2"