mirror of
https://github.com/Redocly/redoc.git
synced 2025-02-19 19:30:32 +03:00
feat: add support prefix items
This commit is contained in:
parent
eb0917d002
commit
27a9dbaf46
|
@ -1242,6 +1242,26 @@ components:
|
||||||
type: string
|
type: string
|
||||||
contentEncoding: base64
|
contentEncoding: base64
|
||||||
contentMediaType: image/png
|
contentMediaType: image/png
|
||||||
|
addresses:
|
||||||
|
type: array
|
||||||
|
minItems: 0
|
||||||
|
maxLength: 10
|
||||||
|
prefixItems:
|
||||||
|
- type: object
|
||||||
|
properties:
|
||||||
|
city:
|
||||||
|
type: string
|
||||||
|
minLength: 0
|
||||||
|
country:
|
||||||
|
type: string
|
||||||
|
minLength: 0
|
||||||
|
street:
|
||||||
|
description: includes build/apartment number
|
||||||
|
type: string
|
||||||
|
minLength: 0
|
||||||
|
- type: number
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
if:
|
if:
|
||||||
title: userStatus === 10
|
title: userStatus === 10
|
||||||
properties:
|
properties:
|
||||||
|
|
|
@ -1135,6 +1135,26 @@ components:
|
||||||
description: User status
|
description: User status
|
||||||
type: integer
|
type: integer
|
||||||
format: int32
|
format: int32
|
||||||
|
addresses:
|
||||||
|
type: array
|
||||||
|
minItems: 0
|
||||||
|
maxLength: 10
|
||||||
|
items:
|
||||||
|
- type: object
|
||||||
|
properties:
|
||||||
|
city:
|
||||||
|
type: string
|
||||||
|
minLength: 0
|
||||||
|
country:
|
||||||
|
type: string
|
||||||
|
minLength: 0
|
||||||
|
street:
|
||||||
|
description: includes build/apartment number
|
||||||
|
type: string
|
||||||
|
minLength: 0
|
||||||
|
- type: number
|
||||||
|
additionalItems:
|
||||||
|
type: string
|
||||||
xml:
|
xml:
|
||||||
name: User
|
name: User
|
||||||
requestBodies:
|
requestBodies:
|
||||||
|
|
|
@ -14,7 +14,7 @@ export function ArrayItemDetails({ schema }: { schema: SchemaModel }) {
|
||||||
((!schema?.pattern || hideSchemaPattern) &&
|
((!schema?.pattern || hideSchemaPattern) &&
|
||||||
!schema.items &&
|
!schema.items &&
|
||||||
!schema.displayFormat &&
|
!schema.displayFormat &&
|
||||||
!schema.constraints.length)
|
!schema.constraints.length) // return null for cases where all constraints are empty
|
||||||
) {
|
) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { ArrayClosingLabel, ArrayOpenningLabel } from '../../common-elements';
|
||||||
import styled from '../../styled-components';
|
import styled from '../../styled-components';
|
||||||
import { humanizeConstraints } from '../../utils';
|
import { humanizeConstraints } from '../../utils';
|
||||||
import { TypeName } from '../../common-elements/fields';
|
import { TypeName } from '../../common-elements/fields';
|
||||||
|
import { ObjectSchema } from './ObjectSchema';
|
||||||
|
|
||||||
const PaddedSchema = styled.div`
|
const PaddedSchema = styled.div`
|
||||||
padding-left: ${({ theme }) => theme.spacing.unit * 2}px;
|
padding-left: ${({ theme }) => theme.spacing.unit * 2}px;
|
||||||
|
@ -21,6 +22,9 @@ export class ArraySchema extends React.PureComponent<SchemaProps> {
|
||||||
? ''
|
? ''
|
||||||
: `(${humanizeConstraints(schema)})`;
|
: `(${humanizeConstraints(schema)})`;
|
||||||
|
|
||||||
|
if (schema.fields) {
|
||||||
|
return <ObjectSchema {...(this.props as any)} level={this.props.level} />;
|
||||||
|
}
|
||||||
if (schema.displayType && !itemsSchema && !minMaxItems.length) {
|
if (schema.displayType && !itemsSchema && !minMaxItems.length) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { OpenAPIRef, OpenAPISchema, OpenAPISpec, Referenced } from '../types';
|
import { OpenAPIRef, OpenAPISchema, OpenAPISpec, Referenced } from '../types';
|
||||||
|
|
||||||
import { appendToMdHeading, isArray, IS_BROWSER } from '../utils/';
|
import { appendToMdHeading, isArray, isBoolean, IS_BROWSER } from '../utils/';
|
||||||
import { JsonPointer } from '../utils/JsonPointer';
|
import { JsonPointer } from '../utils/JsonPointer';
|
||||||
import {
|
import {
|
||||||
getDefinitionName,
|
getDefinitionName,
|
||||||
|
@ -318,9 +318,19 @@ export class OpenAPIParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (items !== undefined) {
|
if (items !== undefined) {
|
||||||
receiver.items = receiver.items || {};
|
const receiverItems = isBoolean(receiver.items)
|
||||||
|
? { items: receiver.items }
|
||||||
|
: receiver.items
|
||||||
|
? (Object.assign({}, receiver.items) as OpenAPISchema)
|
||||||
|
: {};
|
||||||
|
const subSchemaItems = isBoolean(items)
|
||||||
|
? { items }
|
||||||
|
: (Object.assign({}, items) as OpenAPISchema);
|
||||||
// merge inner properties
|
// merge inner properties
|
||||||
receiver.items = this.mergeAllOf({ allOf: [receiver.items, items] }, $ref + '/items');
|
receiver.items = this.mergeAllOf(
|
||||||
|
{ allOf: [receiverItems, subSchemaItems] },
|
||||||
|
$ref + '/items',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (required !== undefined) {
|
if (required !== undefined) {
|
||||||
|
|
154
src/services/__tests__/fixtures/3.1/prefixItems.json
Normal file
154
src/services/__tests__/fixtures/3.1/prefixItems.json
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
{
|
||||||
|
"openapi": "3.1.0",
|
||||||
|
"info": {
|
||||||
|
"title": "Schema definition with prefixItems",
|
||||||
|
"version": "1.0.0"
|
||||||
|
},
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"url": "example.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"components": {
|
||||||
|
"schemas": {
|
||||||
|
"Case1": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"maxItems": 10,
|
||||||
|
"prefixItems": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 0,
|
||||||
|
"maxLength": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/Cat"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"items": false
|
||||||
|
},
|
||||||
|
"Case2": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"maxItems": 10,
|
||||||
|
"prefixItems": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 0,
|
||||||
|
"maxLength": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/Cat"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"items": true
|
||||||
|
},
|
||||||
|
"Case3": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"maxItems": 10,
|
||||||
|
"prefixItems": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 0,
|
||||||
|
"maxLength": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/Cat"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/Dog"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Case4": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"maxItems": 10,
|
||||||
|
"prefixItems": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 0,
|
||||||
|
"maxLength": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/Cat"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"firstItem": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Case5": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"maxItems": 10,
|
||||||
|
"prefixItems": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 0,
|
||||||
|
"maxLength": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/Cat"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"type": "array",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Cat": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"color": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Dog": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"size": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
154
src/services/__tests__/fixtures/arrayItems.json
Normal file
154
src/services/__tests__/fixtures/arrayItems.json
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
{
|
||||||
|
"openapi": "3.0.0",
|
||||||
|
"info": {
|
||||||
|
"title": "Schema definition with array items",
|
||||||
|
"version": "1.0.0"
|
||||||
|
},
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"url": "example.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"components": {
|
||||||
|
"schemas": {
|
||||||
|
"Case1": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"maxItems": 10,
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 0,
|
||||||
|
"maxLength": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/Cat"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"additionalItems": false
|
||||||
|
},
|
||||||
|
"Case2": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"maxItems": 10,
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 0,
|
||||||
|
"maxLength": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/Cat"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"additionalItems": true
|
||||||
|
},
|
||||||
|
"Case3": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"maxItems": 10,
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 0,
|
||||||
|
"maxLength": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/Cat"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"additionalItems": {
|
||||||
|
"$ref": "#/components/schemas/Dog"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Case4": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"maxItems": 10,
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 0,
|
||||||
|
"maxLength": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/Cat"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"additionalItems": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"firstItem": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Case5": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"maxItems": 10,
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 0,
|
||||||
|
"maxLength": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/Cat"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"additionalItems": {
|
||||||
|
"type": "array",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Cat": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"color": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Dog": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"size": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -113,5 +113,105 @@ describe('Models', () => {
|
||||||
expect(schema.fields![1].kind).toEqual('patternProperties');
|
expect(schema.fields![1].kind).toEqual('patternProperties');
|
||||||
expect(schema.fields![1].schema.type).toEqual('object');
|
expect(schema.fields![1].schema.type).toEqual('object');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('type array', () => {
|
||||||
|
function testImmutablePart(schema: SchemaModel) {
|
||||||
|
expect(schema.minItems).toEqual(1);
|
||||||
|
expect(schema.maxItems).toEqual(10);
|
||||||
|
expect(schema.fields![0].schema.type).toEqual('string');
|
||||||
|
expect(schema.fields![1].schema.type).toEqual('number');
|
||||||
|
}
|
||||||
|
const eachArray = ['../fixtures/3.1/prefixItems.json', '../fixtures/arrayItems.json'];
|
||||||
|
|
||||||
|
test.each(eachArray)(
|
||||||
|
'schemaDefinition should resolve prefixItems without additional items',
|
||||||
|
specFixture => {
|
||||||
|
const spec = require(specFixture);
|
||||||
|
const parser = new OpenAPIParser(spec, undefined, opts);
|
||||||
|
const schema = new SchemaModel(parser, spec.components.schemas.Case1, '', opts);
|
||||||
|
|
||||||
|
testImmutablePart(schema);
|
||||||
|
|
||||||
|
expect(schema.fields).toHaveLength(3);
|
||||||
|
expect(schema.fields![2].name).toEqual('[2]');
|
||||||
|
expect(schema.fields![2].schema.pointer).toEqual('#/components/schemas/Cat');
|
||||||
|
expect(schema.fields![2].schema.type).toEqual('object');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
test.each(eachArray)(
|
||||||
|
'schemaDefinition should resolve prefixItems with additional items',
|
||||||
|
specFixture => {
|
||||||
|
const spec = require(specFixture);
|
||||||
|
const parser = new OpenAPIParser(spec, undefined, opts);
|
||||||
|
const schema = new SchemaModel(parser, spec.components.schemas.Case2, '', opts);
|
||||||
|
|
||||||
|
testImmutablePart(schema);
|
||||||
|
|
||||||
|
expect(schema.fields).toHaveLength(4);
|
||||||
|
expect(schema.fields![3].name).toEqual('[3...]');
|
||||||
|
expect(schema.fields![2].schema.type).toEqual('object');
|
||||||
|
expect(schema.fields![2].schema.pointer).toEqual('#/components/schemas/Cat');
|
||||||
|
expect(schema.fields![3].schema.type).toEqual('any');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
test.each(eachArray)(
|
||||||
|
'schemaDefinition should resolve prefixItems with additional items with $ref',
|
||||||
|
specFixture => {
|
||||||
|
const spec = require(specFixture);
|
||||||
|
const parser = new OpenAPIParser(spec, undefined, opts);
|
||||||
|
const schema = new SchemaModel(parser, spec.components.schemas.Case3, '', opts);
|
||||||
|
|
||||||
|
testImmutablePart(schema);
|
||||||
|
|
||||||
|
expect(schema.fields).toHaveLength(4);
|
||||||
|
expect(schema.fields![3].name).toEqual('[3...]');
|
||||||
|
expect(schema.fields![2].schema.type).toEqual('object');
|
||||||
|
expect(schema.fields![2].schema.pointer).toEqual('#/components/schemas/Cat');
|
||||||
|
expect(schema.fields![3].schema.type).toEqual('object');
|
||||||
|
expect(schema.fields![3].schema.pointer).toEqual('#/components/schemas/Dog');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
test.each(eachArray)(
|
||||||
|
'schemaDefinition should resolve prefixItems with additional schema items',
|
||||||
|
specFixture => {
|
||||||
|
const spec = require(specFixture);
|
||||||
|
const parser = new OpenAPIParser(spec, undefined, opts);
|
||||||
|
const schema = new SchemaModel(parser, spec.components.schemas.Case4, '', opts);
|
||||||
|
|
||||||
|
testImmutablePart(schema);
|
||||||
|
|
||||||
|
expect(schema.fields).toHaveLength(4);
|
||||||
|
expect(schema.fields![3].name).toEqual('[3...]');
|
||||||
|
expect(schema.fields![2].schema.type).toEqual('object');
|
||||||
|
expect(schema.fields![2].schema.pointer).toEqual('#/components/schemas/Cat');
|
||||||
|
expect(schema.fields![3].schema.type).toEqual('object');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
test.each(eachArray)(
|
||||||
|
'schemaDefinition should resolve prefixItems with additional array items',
|
||||||
|
specFixture => {
|
||||||
|
const spec = require(specFixture);
|
||||||
|
const parser = new OpenAPIParser(spec, undefined, opts);
|
||||||
|
const schema = new SchemaModel(parser, spec.components.schemas.Case5, '', opts);
|
||||||
|
|
||||||
|
testImmutablePart(schema);
|
||||||
|
|
||||||
|
expect(schema.fields).toHaveLength(4);
|
||||||
|
expect(schema.fields![3].name).toEqual('[3...]');
|
||||||
|
expect(schema.fields![2].schema.type).toEqual('object');
|
||||||
|
expect(schema.fields![2].schema.pointer).toEqual('#/components/schemas/Cat');
|
||||||
|
expect(schema.fields![3].schema.type).toEqual('array');
|
||||||
|
expect(schema.fields![3].schema.fields).toHaveLength(1);
|
||||||
|
expect(schema.fields![3].schema.fields![0].schema.type).toEqual('string');
|
||||||
|
expect(schema.fields![3].schema.fields![0].schema.constraints).toEqual([
|
||||||
|
'>= 0 characters',
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,7 +12,9 @@ import {
|
||||||
extractExtensions,
|
extractExtensions,
|
||||||
humanizeConstraints,
|
humanizeConstraints,
|
||||||
isArray,
|
isArray,
|
||||||
|
isBoolean,
|
||||||
isNamedDefinition,
|
isNamedDefinition,
|
||||||
|
isObject,
|
||||||
isPrimitiveType,
|
isPrimitiveType,
|
||||||
JsonPointer,
|
JsonPointer,
|
||||||
pluralizeType,
|
pluralizeType,
|
||||||
|
@ -188,17 +190,31 @@ export class SchemaModel {
|
||||||
|
|
||||||
if (this.hasType('object')) {
|
if (this.hasType('object')) {
|
||||||
this.fields = buildFields(parser, schema, this.pointer, this.options);
|
this.fields = buildFields(parser, schema, this.pointer, this.options);
|
||||||
} else if (this.hasType('array') && schema.items) {
|
} else if (this.hasType('array')) {
|
||||||
this.items = new SchemaModel(parser, schema.items, this.pointer + '/items', this.options);
|
if (isArray(schema.items) || isArray(schema.prefixItems)) {
|
||||||
this.displayType = pluralizeType(this.items.displayType);
|
this.fields = buildFields(parser, schema, this.pointer, this.options);
|
||||||
this.displayFormat = this.items.format;
|
} else if (isObject(schema.items)) {
|
||||||
this.typePrefix = this.items.typePrefix + l('arrayOf');
|
this.items = new SchemaModel(
|
||||||
this.title = this.title || this.items.title;
|
parser,
|
||||||
this.isPrimitive = this.items.isPrimitive;
|
schema.items as OpenAPISchema,
|
||||||
if (this.example === undefined && this.items.example !== undefined) {
|
this.pointer + '/items',
|
||||||
|
this.options,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.displayType =
|
||||||
|
schema.prefixItems || isArray(schema.items)
|
||||||
|
? 'items'
|
||||||
|
: pluralizeType(this.items?.displayType || this.displayType);
|
||||||
|
this.displayFormat = this.items?.format || '';
|
||||||
|
this.typePrefix = this.items?.typePrefix || '' + l('arrayOf');
|
||||||
|
this.title = this.title || this.items?.title || '';
|
||||||
|
this.isPrimitive = this.items?.isPrimitive || this.isPrimitive;
|
||||||
|
|
||||||
|
if (this.example === undefined && this.items?.example !== undefined) {
|
||||||
this.example = [this.items.example];
|
this.example = [this.items.example];
|
||||||
}
|
}
|
||||||
if (this.items.isPrimitive) {
|
if (this.items?.isPrimitive) {
|
||||||
this.enum = this.items.enum;
|
this.enum = this.items.enum;
|
||||||
}
|
}
|
||||||
if (isArray(this.type)) {
|
if (isArray(this.type)) {
|
||||||
|
@ -400,9 +416,10 @@ function buildFields(
|
||||||
$ref: string,
|
$ref: string,
|
||||||
options: RedocNormalizedOptions,
|
options: RedocNormalizedOptions,
|
||||||
): FieldModel[] {
|
): FieldModel[] {
|
||||||
const props = schema.properties || {};
|
const props = schema.properties || schema.prefixItems || schema.items || {};
|
||||||
const patternProps = schema.patternProperties || {};
|
const patternProps = schema.patternProperties || {};
|
||||||
const additionalProps = schema.additionalProperties || schema.unevaluatedProperties;
|
const additionalProps = schema.additionalProperties || schema.unevaluatedProperties;
|
||||||
|
const itemsProps = schema.prefixItems ? schema.items : schema.additionalItems;
|
||||||
const defaults = schema.default;
|
const defaults = schema.default;
|
||||||
let fields = Object.keys(props || []).map(fieldName => {
|
let fields = Object.keys(props || []).map(fieldName => {
|
||||||
let field = props[fieldName];
|
let field = props[fieldName];
|
||||||
|
@ -420,7 +437,7 @@ function buildFields(
|
||||||
return new FieldModel(
|
return new FieldModel(
|
||||||
parser,
|
parser,
|
||||||
{
|
{
|
||||||
name: fieldName,
|
name: schema.properties ? fieldName : `[${fieldName}]`,
|
||||||
required,
|
required,
|
||||||
schema: {
|
schema: {
|
||||||
...field,
|
...field,
|
||||||
|
@ -484,9 +501,82 @@ function buildFields(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fields.push(
|
||||||
|
...buildAdditionalItems({
|
||||||
|
parser,
|
||||||
|
schema: itemsProps,
|
||||||
|
fieldsCount: fields.length,
|
||||||
|
$ref,
|
||||||
|
options,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
return fields;
|
return fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildAdditionalItems({
|
||||||
|
parser,
|
||||||
|
schema = false,
|
||||||
|
fieldsCount,
|
||||||
|
$ref,
|
||||||
|
options,
|
||||||
|
}: {
|
||||||
|
parser: OpenAPIParser;
|
||||||
|
schema?: OpenAPISchema | OpenAPISchema[] | boolean;
|
||||||
|
fieldsCount: number;
|
||||||
|
$ref: string;
|
||||||
|
options: RedocNormalizedOptions;
|
||||||
|
}) {
|
||||||
|
if (isBoolean(schema)) {
|
||||||
|
return schema
|
||||||
|
? [
|
||||||
|
new FieldModel(
|
||||||
|
parser,
|
||||||
|
{
|
||||||
|
name: `[${fieldsCount}...]`,
|
||||||
|
schema: {},
|
||||||
|
},
|
||||||
|
`${$ref}/additionalItems`,
|
||||||
|
options,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
: [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isArray(schema)) {
|
||||||
|
return [
|
||||||
|
...schema.map(
|
||||||
|
(field, idx) =>
|
||||||
|
new FieldModel(
|
||||||
|
parser,
|
||||||
|
{
|
||||||
|
name: `[${fieldsCount + idx}]`,
|
||||||
|
schema: field,
|
||||||
|
},
|
||||||
|
`${$ref}/additionalItems`,
|
||||||
|
options,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isObject(schema)) {
|
||||||
|
return [
|
||||||
|
new FieldModel(
|
||||||
|
parser,
|
||||||
|
{
|
||||||
|
name: `[${fieldsCount}...]`,
|
||||||
|
schema: schema,
|
||||||
|
},
|
||||||
|
`${$ref}/additionalItems`,
|
||||||
|
options,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
function getDiscriminator(schema: OpenAPISchema): OpenAPISchema['discriminator'] {
|
function getDiscriminator(schema: OpenAPISchema): OpenAPISchema['discriminator'] {
|
||||||
return schema.discriminator || schema['x-discriminator'];
|
return schema.discriminator || schema['x-discriminator'];
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,7 +118,7 @@ export interface OpenAPISchema {
|
||||||
unevaluatedProperties?: boolean | OpenAPISchema;
|
unevaluatedProperties?: boolean | OpenAPISchema;
|
||||||
description?: string;
|
description?: string;
|
||||||
default?: any;
|
default?: any;
|
||||||
items?: OpenAPISchema;
|
items?: OpenAPISchema | OpenAPISchema[] | boolean;
|
||||||
required?: string[];
|
required?: string[];
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
writeOnly?: boolean;
|
writeOnly?: boolean;
|
||||||
|
@ -156,6 +156,8 @@ export interface OpenAPISchema {
|
||||||
const?: string;
|
const?: string;
|
||||||
contentEncoding?: string;
|
contentEncoding?: string;
|
||||||
contentMediaType?: string;
|
contentMediaType?: string;
|
||||||
|
prefixItems?: OpenAPISchema[];
|
||||||
|
additionalItems?: OpenAPISchema | boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OpenAPIDiscriminator {
|
export interface OpenAPIDiscriminator {
|
||||||
|
|
|
@ -352,6 +352,37 @@ Object {
|
||||||
},
|
},
|
||||||
"User": Object {
|
"User": Object {
|
||||||
"properties": Object {
|
"properties": Object {
|
||||||
|
"addresses": Object {
|
||||||
|
"additionalItems": Object {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"items": Array [
|
||||||
|
Object {
|
||||||
|
"properties": Object {
|
||||||
|
"city": Object {
|
||||||
|
"minLength": 0,
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"country": Object {
|
||||||
|
"minLength": 0,
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"street": Object {
|
||||||
|
"description": "includes build/apartment number",
|
||||||
|
"minLength": 0,
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"type": "object",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"type": "number",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"maxLength": 10,
|
||||||
|
"minItems": 0,
|
||||||
|
"type": "array",
|
||||||
|
},
|
||||||
"email": Object {
|
"email": Object {
|
||||||
"description": "User email address",
|
"description": "User email address",
|
||||||
"example": "john.smith@example.com",
|
"example": "john.smith@example.com",
|
||||||
|
@ -2257,6 +2288,37 @@ Object {
|
||||||
"title": "userStatus === 10",
|
"title": "userStatus === 10",
|
||||||
},
|
},
|
||||||
"properties": Object {
|
"properties": Object {
|
||||||
|
"addresses": Object {
|
||||||
|
"items": Object {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"maxLength": 10,
|
||||||
|
"minItems": 0,
|
||||||
|
"prefixItems": Array [
|
||||||
|
Object {
|
||||||
|
"properties": Object {
|
||||||
|
"city": Object {
|
||||||
|
"minLength": 0,
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"country": Object {
|
||||||
|
"minLength": 0,
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"street": Object {
|
||||||
|
"description": "includes build/apartment number",
|
||||||
|
"minLength": 0,
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"type": "object",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"type": "number",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"type": "array",
|
||||||
|
},
|
||||||
"email": Object {
|
"email": Object {
|
||||||
"description": "User email address",
|
"description": "User email address",
|
||||||
"example": "john.smith@example.com",
|
"example": "john.smith@example.com",
|
||||||
|
|
|
@ -107,7 +107,7 @@ export const mergeObjects = (target: any, ...sources: any[]): any => {
|
||||||
return mergeObjects(target, ...sources);
|
return mergeObjects(target, ...sources);
|
||||||
};
|
};
|
||||||
|
|
||||||
const isObject = (item: any): boolean => {
|
export const isObject = (item: unknown): item is Record<string, unknown> => {
|
||||||
return item !== null && typeof item === 'object';
|
return item !== null && typeof item === 'object';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -210,6 +210,10 @@ export function unescapeHTMLChars(str: string): string {
|
||||||
.replace(/"/g, '"');
|
.replace(/"/g, '"');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isArray(value: unknown): value is Array<any> {
|
export function isArray(value: unknown): value is any[] {
|
||||||
return Array.isArray(value);
|
return Array.isArray(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isBoolean(value: unknown): value is boolean {
|
||||||
|
return typeof value === 'boolean';
|
||||||
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ import {
|
||||||
Referenced,
|
Referenced,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import { IS_BROWSER } from './dom';
|
import { IS_BROWSER } from './dom';
|
||||||
import { isNumeric, removeQueryString, resolveUrl, isArray } from './helpers';
|
import { isNumeric, removeQueryString, resolveUrl, isArray, isBoolean } from './helpers';
|
||||||
|
|
||||||
function isWildcardStatusCode(statusCode: string | number): statusCode is string {
|
function isWildcardStatusCode(statusCode: string | number): statusCode is string {
|
||||||
return typeof statusCode === 'string' && /\dxx/i.test(statusCode);
|
return typeof statusCode === 'string' && /\dxx/i.test(statusCode);
|
||||||
|
@ -139,8 +139,13 @@ export function isPrimitiveType(
|
||||||
: schema.additionalProperties === undefined && schema.unevaluatedProperties === undefined;
|
: schema.additionalProperties === undefined && schema.unevaluatedProperties === undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isArray(schema.items) || isArray(schema.prefixItems)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
schema.items !== undefined &&
|
schema.items !== undefined &&
|
||||||
|
!isBoolean(schema.items) &&
|
||||||
(type === 'array' || (isArrayType && type?.includes('array')))
|
(type === 'array' || (isArrayType && type?.includes('array')))
|
||||||
) {
|
) {
|
||||||
isPrimitive = isPrimitiveType(schema.items, schema.items.type);
|
isPrimitive = isPrimitiveType(schema.items, schema.items.type);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user