mirror of
https://github.com/Redocly/redoc.git
synced 2024-11-22 00:26:34 +03:00
feat: Support OAS 3.1 unevaluatedProperties (#1978)
This commit is contained in:
parent
60bc603e9b
commit
0755ac6f04
|
@ -305,6 +305,9 @@ paths:
|
|||
content:
|
||||
application/json:
|
||||
schema:
|
||||
unevaluatedProperties:
|
||||
type: integer
|
||||
format: int32
|
||||
$ref: '#/components/schemas/ApiResponse'
|
||||
security:
|
||||
- petstore_auth:
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
{
|
||||
"openapi": "3.1.0",
|
||||
"info": {
|
||||
"title": "Schema definition with unevaluatedProperties",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"url": "example.com"
|
||||
}
|
||||
],
|
||||
"components": {
|
||||
"schemas": {
|
||||
"Test": {
|
||||
"type": "object",
|
||||
"unevaluatedProperties": true,
|
||||
"properties": {
|
||||
"$ref": "#/components/schemas/Cat"
|
||||
}
|
||||
},
|
||||
"Test2": {
|
||||
"type": "object",
|
||||
"unevaluatedProperties": true,
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/Cat"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Dog"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Test3": {
|
||||
"type": "object",
|
||||
"unevaluatedProperties": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"properties": {
|
||||
"$ref": "#/components/schemas/Cat"
|
||||
}
|
||||
},
|
||||
"Cat": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"color": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Dog": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"size": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -48,5 +48,33 @@ describe('Models', () => {
|
|||
expect(schema.fields).toHaveLength(1);
|
||||
expect(schema.pointer).toBe('#/components/schemas/Child');
|
||||
});
|
||||
|
||||
test('schemaDefinition should resolve unevaluatedProperties in properties', () => {
|
||||
const spec = require('../fixtures/3.1/unevaluatedProperties.json');
|
||||
parser = new OpenAPIParser(spec, undefined, opts);
|
||||
const schema = new SchemaModel(parser, spec.components.schemas.Test, '', opts);
|
||||
expect(schema.fields).toHaveLength(2);
|
||||
expect(schema.fields![1].kind).toEqual('additionalProperties');
|
||||
expect(schema.fields![1].schema.type).toEqual('any');
|
||||
});
|
||||
|
||||
test('schemaDefinition should resolve unevaluatedProperties in anyOf', () => {
|
||||
const spec = require('../fixtures/3.1/unevaluatedProperties.json');
|
||||
parser = new OpenAPIParser(spec, undefined, opts);
|
||||
const schema = new SchemaModel(parser, spec.components.schemas.Test2, '', opts);
|
||||
expect(schema.oneOf![0].fields).toHaveLength(2);
|
||||
expect(schema.oneOf![0].fields![1].kind).toEqual('additionalProperties');
|
||||
expect(schema.oneOf![1].fields).toHaveLength(2);
|
||||
expect(schema.oneOf![1].fields![1].kind).toEqual('additionalProperties');
|
||||
});
|
||||
|
||||
test('schemaDefinition should resolve unevaluatedProperties type boolean', () => {
|
||||
const spec = require('../fixtures/3.1/unevaluatedProperties.json');
|
||||
parser = new OpenAPIParser(spec, undefined, opts);
|
||||
const schema = new SchemaModel(parser, spec.components.schemas.Test3, '', opts);
|
||||
expect(schema.fields).toHaveLength(2);
|
||||
expect(schema.fields![1].kind).toEqual('additionalProperties');
|
||||
expect(schema.fields![1].schema.type).toEqual('boolean');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -364,7 +364,7 @@ function buildFields(
|
|||
options: RedocNormalizedOptions,
|
||||
): FieldModel[] {
|
||||
const props = schema.properties || {};
|
||||
const additionalProps = schema.additionalProperties;
|
||||
const additionalProps = schema.additionalProperties || schema.unevaluatedProperties;
|
||||
const defaults = schema.default;
|
||||
let fields = Object.keys(props || []).map(fieldName => {
|
||||
let field = props[fieldName];
|
||||
|
|
|
@ -114,6 +114,7 @@ export interface OpenAPISchema {
|
|||
type?: string | string[];
|
||||
properties?: { [name: string]: OpenAPISchema };
|
||||
additionalProperties?: boolean | OpenAPISchema;
|
||||
unevaluatedProperties?: boolean | OpenAPISchema;
|
||||
description?: string;
|
||||
default?: any;
|
||||
items?: OpenAPISchema;
|
||||
|
|
|
@ -2776,6 +2776,10 @@ try {
|
|||
"application/json": Object {
|
||||
"schema": Object {
|
||||
"$ref": "#/components/schemas/ApiResponse",
|
||||
"unevaluatedProperties": Object {
|
||||
"format": "int32",
|
||||
"type": "integer",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -146,7 +146,14 @@ describe('Utils', () => {
|
|||
string: ['pattern', 'minLength', 'maxLength'],
|
||||
|
||||
array: ['items', 'maxItems', 'minItems', 'uniqueItems'],
|
||||
object: ['maxProperties', 'minProperties', 'required', 'additionalProperties', 'properties'],
|
||||
object: [
|
||||
'maxProperties',
|
||||
'minProperties',
|
||||
'required',
|
||||
'additionalProperties',
|
||||
'unevaluatedProperties',
|
||||
'properties',
|
||||
],
|
||||
};
|
||||
|
||||
Object.keys(tests).forEach(name => {
|
||||
|
@ -212,6 +219,17 @@ describe('Utils', () => {
|
|||
expect(isPrimitiveType(schema)).toEqual(false);
|
||||
});
|
||||
|
||||
it('should return false for array contains array type and schema has items (unevaluatedProperties)', () => {
|
||||
const schema = {
|
||||
type: ['array'],
|
||||
items: {
|
||||
type: 'object',
|
||||
unevaluatedProperties: true,
|
||||
},
|
||||
};
|
||||
expect(isPrimitiveType(schema)).toEqual(false);
|
||||
});
|
||||
|
||||
it('should return false for array contains object and array types and schema has items', () => {
|
||||
const schema = {
|
||||
type: ['array', 'object'],
|
||||
|
@ -223,6 +241,17 @@ describe('Utils', () => {
|
|||
expect(isPrimitiveType(schema)).toEqual(false);
|
||||
});
|
||||
|
||||
it('should return false for array contains object and array types and schema has items (unevaluatedProperties)', () => {
|
||||
const schema = {
|
||||
type: ['array', 'object'],
|
||||
items: {
|
||||
type: 'object',
|
||||
unevaluatedProperties: true,
|
||||
},
|
||||
};
|
||||
expect(isPrimitiveType(schema)).toEqual(false);
|
||||
});
|
||||
|
||||
it('should return false for array contains object and array types and schema has properties', () => {
|
||||
const schema = {
|
||||
type: ['array', 'object'],
|
||||
|
@ -281,6 +310,17 @@ describe('Utils', () => {
|
|||
expect(isPrimitiveType(schema)).toEqual(false);
|
||||
});
|
||||
|
||||
it('should return false for object with unevaluatedProperties', () => {
|
||||
const schema = {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
unevaluatedProperties: true,
|
||||
},
|
||||
};
|
||||
expect(isPrimitiveType(schema)).toEqual(false);
|
||||
});
|
||||
|
||||
it('should work with externally provided type', () => {
|
||||
const schema = {
|
||||
properties: {
|
||||
|
|
|
@ -97,6 +97,7 @@ const schemaKeywordTypes = {
|
|||
minProperties: 'object',
|
||||
required: 'object',
|
||||
additionalProperties: 'object',
|
||||
unevaluatedProperties: 'object',
|
||||
properties: 'object',
|
||||
};
|
||||
|
||||
|
@ -130,7 +131,7 @@ export function isPrimitiveType(
|
|||
isPrimitive =
|
||||
schema.properties !== undefined
|
||||
? Object.keys(schema.properties).length === 0
|
||||
: schema.additionalProperties === undefined;
|
||||
: schema.additionalProperties === undefined && schema.unevaluatedProperties === undefined;
|
||||
}
|
||||
|
||||
if (schema.items !== undefined && (type === 'array' || (isArray && type?.includes('array')))) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user