Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: exclusiveMin/Max shows incorect range #1799

Merged
merged 12 commits into from
Nov 24, 2021
68 changes: 37 additions & 31 deletions src/utils/openapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,10 @@ export function detectType(schema: OpenAPISchema): string {
return 'any';
}

export function isPrimitiveType(schema: OpenAPISchema, type: string | string[] | undefined = schema.type) {
export function isPrimitiveType(
schema: OpenAPISchema,
type: string | string[] | undefined = schema.type,
) {
if (schema.oneOf !== undefined || schema.anyOf !== undefined) {
return false;
}
Expand All @@ -122,9 +125,10 @@ export function isPrimitiveType(schema: OpenAPISchema, type: string | string[] |
const isArray = Array.isArray(type);

if (type === 'object' || (isArray && type?.includes('object'))) {
isPrimitive = schema.properties !== undefined
? Object.keys(schema.properties).length === 0
: schema.additionalProperties === undefined;
isPrimitive =
schema.properties !== undefined
? Object.keys(schema.properties).length === 0
: schema.additionalProperties === undefined;
}

if (schema.items !== undefined && (type === 'array' || (isArray && type?.includes('array')))) {
Expand All @@ -144,10 +148,10 @@ export function isFormUrlEncoded(contentType: string): boolean {

function delimitedEncodeField(fieldVal: any, fieldName: string, delimiter: string): string {
if (Array.isArray(fieldVal)) {
return fieldVal.map(v => v.toString()).join(delimiter);
return fieldVal.map((v) => v.toString()).join(delimiter);
} else if (typeof fieldVal === 'object') {
return Object.keys(fieldVal)
.map(k => `${k}${delimiter}${fieldVal[k]}`)
.map((k) => `${k}${delimiter}${fieldVal[k]}`)
.join(delimiter);
} else {
return fieldName + '=' + fieldVal.toString();
Expand All @@ -160,7 +164,7 @@ function deepObjectEncodeField(fieldVal: any, fieldName: string): string {
return '';
} else if (typeof fieldVal === 'object') {
return Object.keys(fieldVal)
.map(k => `${fieldName}[${k}]=${fieldVal[k]}`)
.map((k) => `${fieldName}[${k}]=${fieldVal[k]}`)
.join('&');
} else {
console.warn('deepObject style cannot be used with non-object value:' + fieldVal.toString());
Expand Down Expand Up @@ -192,7 +196,7 @@ export function urlFormEncodePayload(
throw new Error('Payload must have fields: ' + payload.toString());
} else {
return Object.keys(payload)
.map(fieldName => {
.map((fieldName) => {
const fieldVal = payload[fieldName];
const { style = 'form', explode = true } = encoding[fieldName] || {};
switch (style) {
Expand Down Expand Up @@ -376,7 +380,7 @@ export function isNamedDefinition(pointer?: string): boolean {
export function getDefinitionName(pointer?: string): string | undefined {
if (!pointer) return undefined;
const match = pointer.match(/^#\/components\/(schemas|pathItems)\/([^\/]+)$/);
return match === null ? undefined : match[1]
return match === null ? undefined : match[1];
}

function humanizeMultipleOfConstraint(multipleOf: number | undefined): string | undefined {
Expand Down Expand Up @@ -448,16 +452,18 @@ export function humanizeConstraints(schema: OpenAPISchema): string[] {
numberRange += schema.minimum;
}

if (typeof schema.exclusiveMinimum === 'number' || typeof schema.exclusiveMaximum === 'number') {
let minimum = 0;
let maximum = 0;
if (schema.minimum) minimum = schema.minimum;
if (typeof schema.exclusiveMinimum === 'number') minimum = minimum <= schema.exclusiveMinimum ? minimum : schema.exclusiveMinimum;

if (schema.maximum) maximum = schema.maximum;
if (typeof schema.exclusiveMaximum === 'number') maximum = maximum > schema.exclusiveMaximum ? maximum : schema.exclusiveMaximum;

numberRange = `[${minimum} .. ${maximum}]`
if (typeof schema.exclusiveMinimum === 'number' && typeof schema.exclusiveMaximum === 'number') {
numberRange = '[';
Oprysk marked this conversation as resolved.
Show resolved Hide resolved
numberRange += schema.exclusiveMinimum;
numberRange += ' .. ';
numberRange += schema.exclusiveMaximum;
numberRange += ']';
} else if (typeof schema.exclusiveMinimum === 'number') {
numberRange = '> ';
numberRange += schema.exclusiveMinimum;
} else if (typeof schema.exclusiveMaximum === 'number') {
numberRange = '< ';
numberRange += schema.exclusiveMaximum;
}

if (numberRange !== undefined) {
Expand All @@ -476,7 +482,7 @@ export function sortByRequired(fields: FieldModel[], order: string[] = []) {
const orderedFields: FieldModel[] = [];
const unorderedFields: FieldModel[] = [];

fields.forEach(field => {
fields.forEach((field) => {
if (field.required) {
order.includes(field.name) ? orderedFields.push(field) : unorderedFields.push(field);
} else {
Expand Down Expand Up @@ -504,13 +510,13 @@ export function mergeParams(
operationParams: Array<Referenced<OpenAPIParameter>> = [],
): Array<Referenced<OpenAPIParameter>> {
const operationParamNames = {};
operationParams.forEach(param => {
operationParams.forEach((param) => {
param = parser.shallowDeref(param);
operationParamNames[param.name + '_' + param.in] = true;
});

// filter out path params overridden by operation ones with the same name
pathParams = pathParams.filter(param => {
pathParams = pathParams.filter((param) => {
param = parser.shallowDeref(param);
return !operationParamNames[param.name + '_' + param.in];
});
Expand All @@ -522,7 +528,7 @@ export function mergeSimilarMediaTypes(
types: Record<string, OpenAPIMediaType>,
): Record<string, OpenAPIMediaType> {
const mergedTypes = {};
Object.keys(types).forEach(name => {
Object.keys(types).forEach((name) => {
const mime = types[name];
// ignore content type parameters (e.g. charset) and merge
const normalizedMimeName = name.split(';')[0].trim();
Expand Down Expand Up @@ -570,7 +576,7 @@ export function normalizeServers(
return resolveUrl(baseUrl, url);
}

return servers.map(server => {
return servers.map((server) => {
return {
...server,
url: normalizeUrl(server.url),
Expand All @@ -588,11 +594,11 @@ export function setSecuritySchemePrefix(prefix: string) {
SECURITY_SCHEMES_SECTION_PREFIX = prefix;
}

export const shortenHTTPVerb = verb =>
({
delete: 'del',
options: 'opts',
}[verb] || verb);
export const shortenHTTPVerb = (verb) =>
({
delete: 'del',
options: 'opts',
}[verb] || verb);

export function isRedocExtension(key: string): boolean {
const redocExtensions = {
Expand All @@ -619,7 +625,7 @@ export function extractExtensions(
showExtensions: string[] | true,
): Record<string, any> {
return Object.keys(obj)
.filter(key => {
.filter((key) => {
if (showExtensions === true) {
return key.startsWith('x-') && !isRedocExtension(key);
}
Expand All @@ -634,6 +640,6 @@ export function extractExtensions(
export function pluralizeType(displayType: string): string {
return displayType
.split(' or ')
.map(type => type.replace(/^(string|object|number|integer|array|boolean)s?( ?.*)/, '$1s$2'))
.map((type) => type.replace(/^(string|object|number|integer|array|boolean)s?( ?.*)/, '$1s$2'))
.join(' or ');
}