Skip to content

Commit

Permalink
Updated AllOf support in OpenAPI generator
Browse files Browse the repository at this point in the history
  • Loading branch information
gius committed Feb 2, 2021
1 parent 4e9a698 commit fc58a17
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 31 deletions.
13 changes: 9 additions & 4 deletions packages/apiclient/src/restRequestBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,16 @@ export class RestRequestBuilder {
return this;
}

getQueryString(query: any) {
return stringify(query, this.queryStringOptions ?? RestRequestBuilder.DefaultQueryStringOptions);
getQueryString(query: any, queryStringOptions?: StringifyOptions) {
return stringify(query, queryStringOptions ?? this.queryStringOptions ?? RestRequestBuilder.DefaultQueryStringOptions);
}

appendQuery(url: string, query?: any) {
return query ? `${url}?${this.getQueryString(query)}` : url;
appendQuery(url: string, query?: any, queryStringOptions?: StringifyOptions) {
if (!query) {
return url;
}

const queryString = typeof query === "string" ? query : this.getQueryString(query, queryStringOptions);
return `${url}?${queryString}`;
}
}
13 changes: 3 additions & 10 deletions packages/generator/src/openapi/fileGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@ export default class FileGenerator {
for (const { type } of items) {
if (type instanceof Enum) {
enumWriter.write(type);
} else if (type instanceof InheritedEntity) {
const baseEntity = type.baseEntities.map(x => x.type).filter(x => x instanceof ObjectEntity)[0] as ObjectEntity;
objectWriter.write(type, baseEntity);
} else if (type instanceof ObjectEntity) {
objectWriter.write(type);
} else if (type instanceof InheritedEntity) {
this.handleInheritedEntity(objectWriter, type);
} else if (type instanceof UnionEntity) {
unionWriter.write(type);
}
Expand All @@ -46,12 +47,4 @@ export default class FileGenerator {

progress.stop();
}

private handleInheritedEntity(writer: ObjectEntityWriter, source: InheritedEntity) {
const objects = source.baseEntities.filter(x => x.type instanceof ObjectEntity).map(x => x.type as ObjectEntity);

const properties = objects.slice(1).flatMap(x => x.properties);
const composedEntity = new ObjectEntity(source.name, properties);
writer.write(composedEntity, objects[0]);
}
}
9 changes: 5 additions & 4 deletions packages/generator/src/openapi/models/inheritedEntity.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import NamedObject from "./namedObject";
import EntityProperty from "./entityProperty";
import ObjectEntity from "./objectEntity";
import TypeReference from "./typeReference";

export default class InheritedEntity extends NamedObject {
constructor(name: string, public baseEntities: TypeReference[]) {
super(name);
export default class InheritedEntity extends ObjectEntity {
constructor(name: string, public baseEntities: TypeReference[], properties: EntityProperty[]) {
super(name, properties);
}
}
32 changes: 25 additions & 7 deletions packages/generator/src/openapi/parsers/openApi2Parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,17 +95,31 @@ export default class OpenApi2Parser {

private parseAllOfObject(name: string, definition: OpenAPIV2.SchemaObject) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const innerTypes = definition.allOf!.map((x, i) =>
this.parseSchemaObject(`${name}Parent${i + 1}`, x as OpenAPIV2.SchemaObject | OpenAPIV2.ItemsObject)
const subTypes = definition.allOf!;

const plainObjects = subTypes.filter(
x => !isV2ReferenceObject(x) && x.type === "object" && !x.allOf && !x.oneOf
) as OpenAPIV2.SchemaObject[];

const otherParents = subTypes
.filter(x => !plainObjects.includes(x as any))
.map((x, i) => this.parseSchemaObject(`${name}Parent${i + 1}`, x as OpenAPIV2.SchemaObject));

const properties = plainObjects.flatMap(x => this.extractObjectProperties(name, x));

const entity = new InheritedEntity(name, otherParents, properties);

plainObjects.forEach(object =>
object.required?.forEach(property => entity.addPropertyRestriction(property, Restriction.required, true))
);

const entity = new InheritedEntity(name, innerTypes);
return this.setTypeReference(name, entity);
}

private parseOneOfObject(name: string, definition: OpenAPIV2.SchemaObject) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const innerTypes = definition.oneOf!.map((x, i) =>
const subTypes = definition.oneOf!;
const innerTypes = subTypes.map((x, i) =>
this.parseSchemaObject(`${name}Option${i + 1}`, x as OpenAPIV2.SchemaObject | OpenAPIV2.ItemsObject)
);

Expand All @@ -114,16 +128,20 @@ export default class OpenApi2Parser {
}

private parseObjectWithProperties(name: string, definition: OpenAPIV2.SchemaObject) {
const properties = definition.properties
? Object.entries(definition.properties).map(x => this.parseEntityProperty(name, x[0], x[1]))
: [];
const properties = this.extractObjectProperties(name, definition);

const entity = new ObjectEntity(name, properties);
definition.required?.forEach(property => entity.addPropertyRestriction(property, Restriction.required, true));

return this.setTypeReference(name, entity);
}

private extractObjectProperties(entityName: string, definition: OpenAPIV2.SchemaObject) {
return definition.properties
? Object.entries(definition.properties).map(x => this.parseEntityProperty(entityName, x[0], x[1]))
: [];
}

private parseEntityProperty(
entityName: string,
propertyName: string,
Expand Down
32 changes: 26 additions & 6 deletions packages/generator/src/openapi/parsers/openApi3Parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,31 +91,51 @@ export default class OpenApi3Parser {

private parseAllOfObject(name: string, definition: OpenAPIV3.SchemaObject) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const innerTypes = definition.allOf!.map((x, i) => this.parseSchemaObject(`${name}Parent${i + 1}`, x));
const subTypes = definition.allOf!;

const plainObjects = subTypes.filter(
x => !isV3ReferenceObject(x) && x.type === "object" && !x.allOf && !x.oneOf
) as OpenAPIV3.SchemaObject[];

const otherParents = subTypes
.filter(x => !plainObjects.includes(x as any))
.map((x, i) => this.parseSchemaObject(`${name}Parent${i + 1}`, x));

const properties = plainObjects.flatMap(x => this.extractObjectProperties(name, x));

const entity = new InheritedEntity(name, otherParents, properties);

plainObjects.forEach(object =>
object.required?.forEach(property => entity.addPropertyRestriction(property, Restriction.required, true))
);

const entity = new InheritedEntity(name, innerTypes);
return this.setTypeReference(name, entity);
}

private parseOneOfObject(name: string, definition: OpenAPIV3.SchemaObject) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const innerTypes = definition.oneOf!.map((x, i) => this.parseSchemaObject(`${name}Option${i + 1}`, x));
const subTypes = definition.oneOf!;
const innerTypes = subTypes.map((x, i) => this.parseSchemaObject(`${name}Option${i + 1}`, x));

const entity = new UnionEntity(name, innerTypes);
return this.setTypeReference(name, entity);
}

private parseObjectWithProperties(name: string, definition: OpenAPIV3.SchemaObject) {
const properties = definition.properties
? Object.entries(definition.properties).map(x => this.parseEntityProperty(name, x[0], x[1]))
: [];
const properties = this.extractObjectProperties(name, definition);

const entity = new ObjectEntity(name, properties);
definition.required?.forEach(property => entity.addPropertyRestriction(property, Restriction.required, true));

return this.setTypeReference(name, entity);
}

private extractObjectProperties(entityName: string, definition: OpenAPIV3.SchemaObject) {
return definition.properties
? Object.entries(definition.properties).map(x => this.parseEntityProperty(entityName, x[0], x[1]))
: [];
}

private parseEntityProperty(
entityName: string,
propertyName: string,
Expand Down
1 change: 1 addition & 0 deletions packages/validation/src/automaticEntityValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export default class AutomaticEntityValidator<TTarget extends Record<string, any
continue;
}

// TODO just add warning that the target property is not observable
ensureObservableProperty(target, propertyName, (target as any)[propertyName]);
this.validatedProperties.push(propertyName);

Expand Down

0 comments on commit fc58a17

Please sign in to comment.