mirror of
https://github.com/Redocly/redoc.git
synced 2025-02-17 02:10:39 +03:00
parent
5af6ba7191
commit
65930ad7ee
|
@ -1,7 +1,7 @@
|
||||||
import { resolve as urlResolve } from 'url';
|
import { resolve as urlResolve } from 'url';
|
||||||
|
|
||||||
import { OpenAPIExample, Referenced } from '../../types';
|
import { OpenAPIEncoding, OpenAPIExample, Referenced } from '../../types';
|
||||||
import { isJsonLike } from '../../utils/openapi';
|
import { isFormUrlEncoded, isJsonLike, urlFormEncodePayload } from '../../utils/openapi';
|
||||||
import { OpenAPIParser } from '../OpenAPIParser';
|
import { OpenAPIParser } from '../OpenAPIParser';
|
||||||
|
|
||||||
const externalExamplesCache: { [url: string]: Promise<any> } = {};
|
const externalExamplesCache: { [url: string]: Promise<any> } = {};
|
||||||
|
@ -12,7 +12,12 @@ export class ExampleModel {
|
||||||
description?: string;
|
description?: string;
|
||||||
externalValueUrl?: string;
|
externalValueUrl?: string;
|
||||||
|
|
||||||
constructor(parser: OpenAPIParser, infoOrRef: Referenced<OpenAPIExample>) {
|
constructor(
|
||||||
|
parser: OpenAPIParser,
|
||||||
|
infoOrRef: Referenced<OpenAPIExample>,
|
||||||
|
mime: string,
|
||||||
|
encoding?: { [field: string]: OpenAPIEncoding },
|
||||||
|
) {
|
||||||
const example = parser.deref(infoOrRef);
|
const example = parser.deref(infoOrRef);
|
||||||
this.value = example.value;
|
this.value = example.value;
|
||||||
this.summary = example.summary;
|
this.summary = example.summary;
|
||||||
|
@ -21,6 +26,10 @@ export class ExampleModel {
|
||||||
this.externalValueUrl = urlResolve(parser.specUrl || '', example.externalValue);
|
this.externalValueUrl = urlResolve(parser.specUrl || '', example.externalValue);
|
||||||
}
|
}
|
||||||
parser.exitRef(infoOrRef);
|
parser.exitRef(infoOrRef);
|
||||||
|
|
||||||
|
if (isFormUrlEncoded(mime) && this.value && typeof this.value === 'object') {
|
||||||
|
this.value = urlFormEncodePayload(this.value, encoding);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getExternalValue(mimeType: string): Promise<any> {
|
getExternalValue(mimeType: string): Promise<any> {
|
||||||
|
|
|
@ -30,10 +30,18 @@ export class MediaTypeModel {
|
||||||
this.schema = info.schema && new SchemaModel(parser, info.schema, '', options);
|
this.schema = info.schema && new SchemaModel(parser, info.schema, '', options);
|
||||||
this.onlyRequiredInSamples = options.onlyRequiredInSamples;
|
this.onlyRequiredInSamples = options.onlyRequiredInSamples;
|
||||||
if (info.examples !== undefined) {
|
if (info.examples !== undefined) {
|
||||||
this.examples = mapValues(info.examples, example => new ExampleModel(parser, example));
|
this.examples = mapValues(
|
||||||
|
info.examples,
|
||||||
|
example => new ExampleModel(parser, example, name, info.encoding),
|
||||||
|
);
|
||||||
} else if (info.example !== undefined) {
|
} else if (info.example !== undefined) {
|
||||||
this.examples = {
|
this.examples = {
|
||||||
default: new ExampleModel(parser, { value: parser.shalowDeref(info.example) }),
|
default: new ExampleModel(
|
||||||
|
parser,
|
||||||
|
{ value: parser.shalowDeref(info.example) },
|
||||||
|
name,
|
||||||
|
info.encoding,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
} else if (isJsonLike(name)) {
|
} else if (isJsonLike(name)) {
|
||||||
this.generateExample(parser, info);
|
this.generateExample(parser, info);
|
||||||
|
@ -55,15 +63,25 @@ export class MediaTypeModel {
|
||||||
sample[this.schema.discriminatorProp] = subSchema.title;
|
sample[this.schema.discriminatorProp] = subSchema.title;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.examples[subSchema.title] = new ExampleModel(parser, {
|
this.examples[subSchema.title] = new ExampleModel(
|
||||||
value: sample,
|
parser,
|
||||||
});
|
{
|
||||||
|
value: sample,
|
||||||
|
},
|
||||||
|
this.name,
|
||||||
|
info.encoding,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else if (this.schema) {
|
} else if (this.schema) {
|
||||||
this.examples = {
|
this.examples = {
|
||||||
default: new ExampleModel(parser, {
|
default: new ExampleModel(
|
||||||
value: Sampler.sample(info.schema, samplerOptions, parser.spec),
|
parser,
|
||||||
}),
|
{
|
||||||
|
value: Sampler.sample(info.schema, samplerOptions, parser.spec),
|
||||||
|
},
|
||||||
|
this.name,
|
||||||
|
info.encoding,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { dirname } from 'path';
|
||||||
|
|
||||||
import { OpenAPIParser } from '../services/OpenAPIParser';
|
import { OpenAPIParser } from '../services/OpenAPIParser';
|
||||||
import {
|
import {
|
||||||
|
OpenAPIEncoding,
|
||||||
OpenAPIMediaType,
|
OpenAPIMediaType,
|
||||||
OpenAPIOperation,
|
OpenAPIOperation,
|
||||||
OpenAPIParameter,
|
OpenAPIParameter,
|
||||||
|
@ -130,6 +131,101 @@ export function isJsonLike(contentType: string): boolean {
|
||||||
return contentType.search(/json/i) !== -1;
|
return contentType.search(/json/i) !== -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isFormUrlEncoded(contentType: string): boolean {
|
||||||
|
return contentType === 'application/x-www-form-urlencoded';
|
||||||
|
}
|
||||||
|
|
||||||
|
function formEncodeField(fieldVal: any, fieldName: string, explode: boolean): string {
|
||||||
|
if (!fieldVal || !fieldVal.length) {
|
||||||
|
return fieldName + '=';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(fieldVal)) {
|
||||||
|
if (explode) {
|
||||||
|
return fieldVal.map(val => `${fieldName}=${val}`).join('&');
|
||||||
|
} else {
|
||||||
|
return fieldName + '=' + fieldVal.map(val => val.toString()).join(',');
|
||||||
|
}
|
||||||
|
} else if (typeof fieldVal === 'object') {
|
||||||
|
if (explode) {
|
||||||
|
return Object.keys(fieldVal)
|
||||||
|
.map(k => `${k}=${fieldVal[k]}`)
|
||||||
|
.join('&');
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
fieldName +
|
||||||
|
'=' +
|
||||||
|
Object.keys(fieldVal)
|
||||||
|
.map(k => `${k},${fieldVal[k]}`)
|
||||||
|
.join(',')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return fieldName + '=' + fieldVal.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function delimitedEncodeField(fieldVal: any, fieldName: string, delimeter: string): string {
|
||||||
|
if (Array.isArray(fieldVal)) {
|
||||||
|
return fieldVal.map(v => v.toString()).join(delimeter);
|
||||||
|
} else if (typeof fieldVal === 'object') {
|
||||||
|
return Object.keys(fieldVal)
|
||||||
|
.map(k => `${k}${delimeter}${fieldVal[k]}`)
|
||||||
|
.join(delimeter);
|
||||||
|
} else {
|
||||||
|
return fieldName + '=' + fieldVal.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function deepObjectEncodeField(fieldVal: any, fieldName: string): string {
|
||||||
|
if (Array.isArray(fieldVal)) {
|
||||||
|
console.warn('deepObject style cannot be used with array value:' + fieldVal.toString());
|
||||||
|
return '';
|
||||||
|
} else if (typeof fieldVal === 'object') {
|
||||||
|
return Object.keys(fieldVal)
|
||||||
|
.map(k => `${fieldName}[${k}]=${fieldVal[k]}`)
|
||||||
|
.join('&');
|
||||||
|
} else {
|
||||||
|
console.warn('deepObject style cannot be used with non-object value:' + fieldVal.toString());
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Should be used only for url-form-encoded body payloads
|
||||||
|
* To be used for parmaters should be extended with other style values
|
||||||
|
*/
|
||||||
|
export function urlFormEncodePayload(
|
||||||
|
payload: object,
|
||||||
|
encoding: { [field: string]: OpenAPIEncoding } = {},
|
||||||
|
) {
|
||||||
|
if (Array.isArray(payload)) {
|
||||||
|
throw new Error('Payload must have fields: ' + payload.toString());
|
||||||
|
} else {
|
||||||
|
return Object.keys(payload)
|
||||||
|
.map(fieldName => {
|
||||||
|
const fieldVal = payload[fieldName];
|
||||||
|
const { style = 'form', explode = true } = encoding[fieldName] || {};
|
||||||
|
switch (style) {
|
||||||
|
case 'form':
|
||||||
|
return formEncodeField(fieldVal, fieldName, explode);
|
||||||
|
break;
|
||||||
|
case 'spaceDelimited':
|
||||||
|
return delimitedEncodeField(fieldVal, fieldName, '%20');
|
||||||
|
case 'pipeDelimited':
|
||||||
|
return delimitedEncodeField(fieldVal, fieldName, '|');
|
||||||
|
case 'deepObject':
|
||||||
|
return deepObjectEncodeField(fieldVal, fieldName);
|
||||||
|
default:
|
||||||
|
// TODO implement rest of styles for path parameters
|
||||||
|
console.warn('Incorrect or unsupported encoding style: ' + style);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.join('&');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function langFromMime(contentType: string): string {
|
export function langFromMime(contentType: string): string {
|
||||||
if (contentType.search(/xml/i) !== -1) {
|
if (contentType.search(/xml/i) !== -1) {
|
||||||
return 'xml';
|
return 'xml';
|
||||||
|
|
Loading…
Reference in New Issue
Block a user