- Fixed #868 where (newly) required properties from base models would not get specified

This commit is contained in:
Ferdi Koomen 2021-10-26 18:31:38 +02:00
parent 73acbca085
commit 918d4844d9
10 changed files with 144 additions and 30 deletions

View File

@ -1,5 +1,8 @@
import type { Enum } from '../../../client/interfaces/Enum';
/**
* @deprecated
*/
export function getEnumFromDescription(description: string): Enum[] {
// Check if we can find this special format string:
// None=0,Something=1,AnotherThing=2

View File

@ -133,13 +133,13 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefiniti
model.base = 'any';
if (definition.properties) {
const properties = getModelProperties(openApi, definition, getModel);
properties.forEach(property => {
model.imports.push(...property.imports);
model.enums.push(...property.enums);
model.properties.push(property);
if (property.export === 'enum') {
model.enums.push(property);
const modelProperties = getModelProperties(openApi, definition, getModel);
modelProperties.forEach(modelProperty => {
model.imports.push(...modelProperty.imports);
model.enums.push(...modelProperty.enums);
model.properties.push(modelProperty);
if (modelProperty.export === 'enum') {
model.enums.push(modelProperty);
}
});
}

View File

@ -1,8 +1,10 @@
import type { Model } from '../../../client/interfaces/Model';
import type { ModelComposition } from '../../../client/interfaces/ModelComposition';
import type { OpenApi } from '../interfaces/OpenApi';
import type { OpenApiSchema } from '../interfaces/OpenApiSchema';
import type { getModel } from './getModel';
import { getModelProperties } from './getModelProperties';
import { getRequiredPropertiesFromComposition } from './getRequiredPropertiesFromComposition';
// Fix for circular dependency
export type GetModelFn = typeof getModel;
@ -15,8 +17,10 @@ export function getModelComposition(openApi: OpenApi, definition: OpenApiSchema,
properties: [],
};
const models = definitions.map(definition => getModel(openApi, definition));
models
const properties: Model[] = [];
definitions
.map(definition => getModel(openApi, definition))
.filter(model => {
const hasProperties = model.properties.length;
const hasEnums = model.enums.length;
@ -30,12 +34,25 @@ export function getModelComposition(openApi: OpenApi, definition: OpenApiSchema,
composition.properties.push(model);
});
if (definition.properties) {
const properties = getModelProperties(openApi, definition, getModel);
properties.forEach(property => {
composition.imports.push(...property.imports);
composition.enums.push(...property.enums);
if (definition.required) {
const requiredProperties = getRequiredPropertiesFromComposition(openApi, definition.required, definitions, getModel);
requiredProperties.forEach(requiredProperty => {
composition.imports.push(...requiredProperty.imports);
composition.enums.push(...requiredProperty.enums);
});
properties.push(...requiredProperties);
}
if (definition.properties) {
const modelProperties = getModelProperties(openApi, definition, getModel);
modelProperties.forEach(modelProperty => {
composition.imports.push(...modelProperty.imports);
composition.enums.push(...modelProperty.enums);
});
properties.push(...modelProperties);
}
if (properties) {
composition.properties.push({
name: 'properties',
export: 'interface',
@ -54,5 +71,6 @@ export function getModelComposition(openApi: OpenApi, definition: OpenApiSchema,
properties,
});
}
return composition;
}

View File

@ -0,0 +1,28 @@
import type { Model } from '../../../client/interfaces/Model';
import type { OpenApi } from '../interfaces/OpenApi';
import type { OpenApiSchema } from '../interfaces/OpenApiSchema';
import type { getModel } from './getModel';
import { getRef } from './getRef';
// Fix for circular dependency
export type GetModelFn = typeof getModel;
export function getRequiredPropertiesFromComposition(openApi: OpenApi, required: string[], definitions: OpenApiSchema[], getModel: GetModelFn): Model[] {
return definitions
.reduce((properties, definition) => {
if (definition.$ref) {
const schema = getRef<OpenApiSchema>(openApi, definition);
return [...properties, ...getModel(openApi, schema).properties];
}
return [...properties, ...getModel(openApi, definition).properties];
}, [] as Model[])
.filter(property => {
return !property.isRequired && required.includes(property.name);
})
.map(property => {
return {
...property,
isRequired: true,
};
});
}

View File

@ -1,5 +1,8 @@
import type { Enum } from '../../../client/interfaces/Enum';
/**
* @deprecated
*/
export function getEnumFromDescription(description: string): Enum[] {
// Check if we can find this special format string:
// None=0,Something=1,AnotherThing=2

View File

@ -160,13 +160,13 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefiniti
model.default = getModelDefault(definition, model);
if (definition.properties) {
const properties = getModelProperties(openApi, definition, getModel);
properties.forEach(property => {
model.imports.push(...property.imports);
model.enums.push(...property.enums);
model.properties.push(property);
if (property.export === 'enum') {
model.enums.push(property);
const modelProperties = getModelProperties(openApi, definition, getModel);
modelProperties.forEach(modelProperty => {
model.imports.push(...modelProperty.imports);
model.enums.push(...modelProperty.enums);
model.properties.push(modelProperty);
if (modelProperty.export === 'enum') {
model.enums.push(modelProperty);
}
});
}

View File

@ -1,8 +1,10 @@
import type { Model } from '../../../client/interfaces/Model';
import type { ModelComposition } from '../../../client/interfaces/ModelComposition';
import type { OpenApi } from '../interfaces/OpenApi';
import type { OpenApiSchema } from '../interfaces/OpenApiSchema';
import type { getModel } from './getModel';
import { getModelProperties } from './getModelProperties';
import { getRequiredPropertiesFromComposition } from './getRequiredPropertiesFromComposition';
// Fix for circular dependency
export type GetModelFn = typeof getModel;
@ -15,8 +17,10 @@ export function getModelComposition(openApi: OpenApi, definition: OpenApiSchema,
properties: [],
};
const models = definitions.map(definition => getModel(openApi, definition));
models
const properties: Model[] = [];
definitions
.map(definition => getModel(openApi, definition))
.filter(model => {
const hasProperties = model.properties.length;
const hasEnums = model.enums.length;
@ -30,12 +34,25 @@ export function getModelComposition(openApi: OpenApi, definition: OpenApiSchema,
composition.properties.push(model);
});
if (definition.properties) {
const properties = getModelProperties(openApi, definition, getModel);
properties.forEach(property => {
composition.imports.push(...property.imports);
composition.enums.push(...property.enums);
if (definition.required) {
const requiredProperties = getRequiredPropertiesFromComposition(openApi, definition.required, definitions, getModel);
requiredProperties.forEach(requiredProperty => {
composition.imports.push(...requiredProperty.imports);
composition.enums.push(...requiredProperty.enums);
});
properties.push(...requiredProperties);
}
if (definition.properties) {
const modelProperties = getModelProperties(openApi, definition, getModel);
modelProperties.forEach(modelProperty => {
composition.imports.push(...modelProperty.imports);
composition.enums.push(...modelProperty.enums);
});
properties.push(...modelProperties);
}
if (properties.length) {
composition.properties.push({
name: 'properties',
export: 'interface',

View File

@ -0,0 +1,28 @@
import type { Model } from '../../../client/interfaces/Model';
import type { OpenApi } from '../interfaces/OpenApi';
import type { OpenApiSchema } from '../interfaces/OpenApiSchema';
import type { getModel } from './getModel';
import { getRef } from './getRef';
// Fix for circular dependency
export type GetModelFn = typeof getModel;
export function getRequiredPropertiesFromComposition(openApi: OpenApi, required: string[], definitions: OpenApiSchema[], getModel: GetModelFn): Model[] {
return definitions
.reduce((properties, definition) => {
if (definition.$ref) {
const schema = getRef<OpenApiSchema>(openApi, definition);
return [...properties, ...getModel(openApi, schema).properties];
}
return [...properties, ...getModel(openApi, definition).properties];
}, [] as Model[])
.filter(property => {
return !property.isRequired && required.includes(property.name);
})
.map(property => {
return {
...property,
isRequired: true,
};
});
}

View File

@ -5,6 +5,7 @@ import { stripNamespace } from './stripNamespace';
function encode(value: string): string {
return value.replace(/^[^a-zA-Z_$]+/g, '').replace(/[^\w$]+/g, '_');
}
/**
* Parse any string value into a type object.
* @param values String or String[] value like "integer", "Link[Model]" or ["string", "null"]

View File

@ -811,7 +811,7 @@ import type { ModelWithString } from './ModelWithString';
export type ModelThatExtends = (ModelWithString & {
propExtendsA?: string;
propExtendsB?: ModelWithString;
});
} & any);
"
`;
@ -829,7 +829,7 @@ import type { ModelWithString } from './ModelWithString';
export type ModelThatExtendsExtends = (ModelWithString & ModelThatExtends & {
propExtendsC?: string;
propExtendsD?: ModelWithString;
});
} & any);
"
`;
@ -1478,6 +1478,9 @@ export const $ModelThatExtends = {
type: 'ModelWithString',
},
},
}, {
properties: {
},
}],
};"
`;
@ -1501,6 +1504,9 @@ export const $ModelThatExtendsExtends = {
type: 'ModelWithString',
},
},
}, {
properties: {
},
}],
};"
`;
@ -3201,6 +3207,8 @@ import type { CompositionBaseModel } from './CompositionBaseModel';
* This is a model that extends the base model
*/
export type CompositionExtendedModel = (CompositionBaseModel & {
firstName: string;
lastname: string;
age: number;
});
"
@ -4055,6 +4063,14 @@ export const $CompositionExtendedModel = {
type: 'CompositionBaseModel',
}, {
properties: {
firstName: {
type: 'string',
isRequired: true,
},
lastname: {
type: 'string',
isRequired: true,
},
age: {
type: 'number',
isRequired: true,