Skip to content

Commit

Permalink
feat: strict array model generate (#130)
Browse files Browse the repository at this point in the history
Co-authored-by: Andrey Klimenko <klimenko.andrei@dxc.com>
  • Loading branch information
KlimenkoAV and Andrey Klimenko authored Oct 30, 2023
1 parent 0968fe6 commit 2528ab5
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 23 deletions.
6 changes: 5 additions & 1 deletion .snapshot/all/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface ICategory {

export interface IProduct {
category: $types.TypeOrUndefinedNullable<ICategory>;
colors: $types.TypeOrUndefined<string[]>;
expireDate: $types.TypeOrUndefined<string>;
externalId: $types.TypeOrUndefinedNullable<string>;
id: $types.TypeOrUndefined<string>;
Expand Down Expand Up @@ -58,17 +59,19 @@ export class Category {

export class Product {
public category: $types.TypeOrUndefinedNullable<Category> = undefined;
public colors: string[] = [];
public expireDate: $types.TypeOrUndefined<Date> = undefined;
public externalId: $types.TypeOrUndefinedNullable<Guid> = undefined;
public id: $types.TypeOrUndefined<Guid> = undefined;
public modifyDates: $types.TypeOrUndefined<Date[]> = undefined;
public modifyDates: Date[] = [];
public name: $types.TypeOrUndefinedNullable<string> = undefined;
public status: $types.TypeOrUndefined<ProductStatus> = undefined;
private __product!: string;

public static toDTO(model: Partial<Product>): 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(),
Expand All @@ -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);
Expand Down
25 changes: 19 additions & 6 deletions __tests__/generators/utils/TypeSerializer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ describe('TypeSerializer tests', () => {
// Arrange
// Act
const result = new TypeSerializer({
type: 'MyType'
type: { name: 'MyType' }
}).toString();

// Assert
Expand All @@ -17,31 +17,44 @@ describe('TypeSerializer tests', () => {
// Arrange
// Act
const result = new TypeSerializer({
type: 'MyType',
type: { name: 'MyType' },
isOptional: false
}).toString();

// Assert
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<MyType[]>');
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();

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
27 changes: 18 additions & 9 deletions src/generators/ModelsGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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) {
Expand All @@ -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;
}
}
}
2 changes: 1 addition & 1 deletion src/generators/angular/AngularServicesMethodGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export class AngularServicesMethodGenerator {
const typeName = `${isModel ? `${MODELS_NAMESPACE}.` : ''}${type}`;

return new TypeSerializer({
type: typeName,
type: { name: typeName },
isCollection,
isOptional
}).toString();
Expand Down
23 changes: 18 additions & 5 deletions src/generators/utils/TypeSerializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,40 @@ 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 {
public static fromInterfaceProperty(param: IInterfacePropertyModel): 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;
Expand All @@ -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);
Expand Down
1 change: 1 addition & 0 deletions src/generators/utils/consts.ts
Original file line number Diff line number Diff line change
@@ -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';
7 changes: 7 additions & 0 deletions swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,13 @@
},
"nullable": true
},
"colors": {
"type": "array",
"items": {
"type": "string"
},
"nullable": true
},
"category": {
"$ref": "#/components/schemas/Category"
},
Expand Down

0 comments on commit 2528ab5

Please sign in to comment.