From 2528ab59d5af1bfdc7aac8bcbc2c5923efe7b5ca Mon Sep 17 00:00:00 2001 From: KlimenkoAV <42928801+KlimenkoAV@users.noreply.github.com> Date: Mon, 30 Oct 2023 19:26:52 +0100 Subject: [PATCH] feat: strict array model generate (#130) Co-authored-by: Andrey Klimenko --- .snapshot/all/models.ts | 6 ++++- .../generators/utils/TypeSerializer.spec.ts | 25 ++++++++++++----- package.json | 2 +- src/generators/ModelsGenerator.ts | 27 ++++++++++++------- .../angular/AngularServicesMethodGenerator.ts | 2 +- src/generators/utils/TypeSerializer.ts | 23 ++++++++++++---- src/generators/utils/consts.ts | 1 + swagger.json | 7 +++++ 8 files changed, 70 insertions(+), 23 deletions(-) diff --git a/.snapshot/all/models.ts b/.snapshot/all/models.ts index 8766559..732690a 100644 --- a/.snapshot/all/models.ts +++ b/.snapshot/all/models.ts @@ -14,6 +14,7 @@ export interface ICategory { export interface IProduct { category: $types.TypeOrUndefinedNullable; + colors: $types.TypeOrUndefined; expireDate: $types.TypeOrUndefined; externalId: $types.TypeOrUndefinedNullable; id: $types.TypeOrUndefined; @@ -58,10 +59,11 @@ export class Category { export class Product { public category: $types.TypeOrUndefinedNullable = undefined; + public colors: string[] = []; public expireDate: $types.TypeOrUndefined = undefined; public externalId: $types.TypeOrUndefinedNullable = undefined; public id: $types.TypeOrUndefined = undefined; - public modifyDates: $types.TypeOrUndefined = undefined; + public modifyDates: Date[] = []; public name: $types.TypeOrUndefinedNullable = undefined; public status: $types.TypeOrUndefined = undefined; private __product!: string; @@ -69,6 +71,7 @@ export class Product { public static toDTO(model: Partial): IProduct { return { category: model.category ? Category.toDTO(model.category) : undefined, + colors: model.colors, expireDate: toDateOut(model.expireDate), externalId: model.externalId ? model.externalId.toString() : null, id: model.id ? model.id.toString() : Guid.empty.toString(), @@ -81,6 +84,7 @@ export class Product { public static fromDTO(dto: IProduct): Product { const model = new Product(); model.category = dto.category ? Category.fromDTO(dto.category) : undefined; + model.colors = dto.colors ? dto.colors : []; model.expireDate = toDateIn(dto.expireDate); model.externalId = dto.externalId ? new Guid(dto.externalId) : null; model.id = new Guid(dto.id); diff --git a/__tests__/generators/utils/TypeSerializer.spec.ts b/__tests__/generators/utils/TypeSerializer.spec.ts index 8a27b26..ec57b97 100644 --- a/__tests__/generators/utils/TypeSerializer.spec.ts +++ b/__tests__/generators/utils/TypeSerializer.spec.ts @@ -6,7 +6,7 @@ describe('TypeSerializer tests', () => { // Arrange // Act const result = new TypeSerializer({ - type: 'MyType' + type: { name: 'MyType' } }).toString(); // Assert @@ -17,7 +17,7 @@ describe('TypeSerializer tests', () => { // Arrange // Act const result = new TypeSerializer({ - type: 'MyType', + type: { name: 'MyType' }, isOptional: false }).toString(); @@ -25,23 +25,36 @@ describe('TypeSerializer tests', () => { expect(result).toEqual('MyType'); }); - test('isCollection should return collection optional type', () => { + test('isCollection should return collection of type', () => { // Arrange // Act const result = new TypeSerializer({ - type: 'MyType', + type: { name: 'MyType' }, isCollection: true }).toString(); // Assert - expect(result).toEqual('$types.TypeOrUndefined'); + expect(result).toEqual('MyType[]'); + }); + + test('isCollection and isOptional should return collection of type', () => { + // Arrange + // Act + const result = new TypeSerializer({ + type: { name: 'MyType' }, + isCollection: true, + isOptional: true + }).toString(); + + // Assert + expect(result).toEqual('MyType[]'); }); test('isNullable should return nullable type', () => { // Arrange // Act const result = new TypeSerializer({ - type: 'MyType', + type: { name: 'MyType' }, isNullable: true }).toString(); diff --git a/package.json b/package.json index 4781dd1..f1382b9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@luxbss/gengen", - "version": "1.2.1", + "version": "1.2.2", "description": "Tool for generating models and Angular services based on OpenAPIs and Swagger's JSON", "bin": { "gengen": "./bin/index.js" diff --git a/src/generators/ModelsGenerator.ts b/src/generators/ModelsGenerator.ts index c480481..d237733 100644 --- a/src/generators/ModelsGenerator.ts +++ b/src/generators/ModelsGenerator.ts @@ -20,7 +20,7 @@ import { PathBuilder } from '../services/PathBuilder'; import { lowerFirst } from '../utils'; import { InterfacesGenerator } from './models-generator/InterfacesGenerator'; import { TypeSerializer } from './utils/TypeSerializer'; -import { NULL_STRING, TYPES_NAMESPACE, UNDEFINED_STRING } from './utils/consts'; +import { ARRAY_STRING, NULL_STRING, TYPES_NAMESPACE, UNDEFINED_STRING } from './utils/consts'; const TO_DTO_METHOD = 'toDTO'; const FROM_DTO_METHOD = 'fromDTO'; @@ -166,8 +166,12 @@ export class ModelsGenerator { kind: StructureKind.Property, scope: Scope.Public, name: objectProperty.name, - type: new TypeSerializer(objectProperty).toString(), - initializer: UNDEFINED_STRING + type: new TypeSerializer({ + type: { name: objectProperty.type }, + isNullable: objectProperty.isNullable, + isCollection: objectProperty.isCollection + }).toString(), + initializer: objectProperty.isCollection ? ARRAY_STRING : UNDEFINED_STRING }) ), this.getGuardProperty(objectModel.name) @@ -229,14 +233,14 @@ export class ModelsGenerator { switch (property.kind) { case PropertyKind.Date: if (property.isCollection) { - return `${dtoProperty} ? ${dtoProperty}.map(toDateIn) : []`; + return `${dtoProperty} ? ${dtoProperty}.map(toDateIn) : ${ARRAY_STRING}`; } return `toDateIn(${dtoProperty})`; case PropertyKind.Guid: if (property.isCollection) { - return `${dtoProperty} ? ${dtoProperty}.map(x => new ${property.type}(x)) : []`; + return `${dtoProperty} ? ${dtoProperty}.map(x => new ${property.type}(x)) : ${ARRAY_STRING}`; } if (property.isNullable) { @@ -247,19 +251,24 @@ export class ModelsGenerator { case PropertyKind.Identity: if (property.isCollection) { - return `${dtoProperty} ? ${dtoProperty}.map(x => new ${property.type}(x.id)) : []`; + return `${dtoProperty} ? ${dtoProperty}.map(x => new ${property.type}(x.id)) : ${ARRAY_STRING}`; } return `${dtoProperty} ? new ${property.type}(${dtoProperty}.id) : ${UNDEFINED_STRING}`; case PropertyKind.Object: if (property.isCollection) { - return `${dtoProperty} ? ${dtoProperty}.map(x => ${property.type}.${FROM_DTO_METHOD}(x)) : []`; + return `${dtoProperty} ? ${dtoProperty}.map(x => ${property.type}.${FROM_DTO_METHOD}(x)) : ${ARRAY_STRING}`; } return `${dtoProperty} ? ${property.type}.${FROM_DTO_METHOD}(${dtoProperty}) : ${UNDEFINED_STRING}`; - } - return dtoProperty; + default: + if (property.isCollection) { + return `${dtoProperty} ? ${dtoProperty} : ${ARRAY_STRING}`; + } + + return dtoProperty; + } } } diff --git a/src/generators/angular/AngularServicesMethodGenerator.ts b/src/generators/angular/AngularServicesMethodGenerator.ts index a1dadf2..3cf9764 100644 --- a/src/generators/angular/AngularServicesMethodGenerator.ts +++ b/src/generators/angular/AngularServicesMethodGenerator.ts @@ -101,7 +101,7 @@ export class AngularServicesMethodGenerator { const typeName = `${isModel ? `${MODELS_NAMESPACE}.` : ''}${type}`; return new TypeSerializer({ - type: typeName, + type: { name: typeName }, isCollection, isOptional }).toString(); diff --git a/src/generators/utils/TypeSerializer.ts b/src/generators/utils/TypeSerializer.ts index 110a706..0d5a3a1 100644 --- a/src/generators/utils/TypeSerializer.ts +++ b/src/generators/utils/TypeSerializer.ts @@ -2,11 +2,16 @@ import { IInterfacePropertyModel } from '../../models/InterfaceModel'; import { TYPES_NAMESPACE } from './consts'; import { typeOrUndefined } from './typeOrUndefined'; +interface IType { + name: string; + isInterface?: boolean; +} + interface ITypeSerializerOptions { isCollection?: boolean; isNullable?: boolean; isOptional?: boolean; - type: string; + type: IType; } export class TypeSerializer { @@ -14,20 +19,23 @@ export class TypeSerializer { return new TypeSerializer({ isCollection: param.isCollection, isNullable: param.isNullable, - type: param.dtoType + type: { + name: param.dtoType, + isInterface: true + } }); } public static fromTypeName(typeName: string): TypeSerializer { return new TypeSerializer({ - type: typeName + type: { name: typeName } }); } private isCollection: boolean; private isNullable: boolean; private isOptional: boolean; - private type: string; + private type: IType; constructor(options: ITypeSerializerOptions) { this.isCollection = options.isCollection ?? false; @@ -37,7 +45,12 @@ export class TypeSerializer { } public toString(): string { - const typeName = this.isCollection ? `${this.type}[]` : this.type; + const typeName = this.isCollection ? `${this.type.name}[]` : this.type.name; + + if (this.isCollection && !this.type.isInterface) { + return typeName; + } + switch (true) { case this.isNullable: return this.typeOrUndefinedNullable(typeName); diff --git a/src/generators/utils/consts.ts b/src/generators/utils/consts.ts index b99b25a..37c84de 100644 --- a/src/generators/utils/consts.ts +++ b/src/generators/utils/consts.ts @@ -1,5 +1,6 @@ export const NULL_STRING = `${null}`; export const UNDEFINED_STRING = `${undefined}`; +export const ARRAY_STRING = '[]'; export const MODELS_NAMESPACE = '$models'; export const MAPPERS_NAMESPACE = '$mappers'; export const TYPES_NAMESPACE = '$types'; \ No newline at end of file diff --git a/swagger.json b/swagger.json index ca95cc1..f07bd31 100644 --- a/swagger.json +++ b/swagger.json @@ -691,6 +691,13 @@ }, "nullable": true }, + "colors": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, "category": { "$ref": "#/components/schemas/Category" },