diff --git a/npm/ng-packs/packages/schematics/src/tests/parse-generic-type.spec.ts b/npm/ng-packs/packages/schematics/src/tests/parse-generic-type.spec.ts new file mode 100644 index 0000000000..400fcdf6eb --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/tests/parse-generic-type.spec.ts @@ -0,0 +1,129 @@ +import { parseBaseTypeWithGenericTypes } from '../utils/model'; +import { parseGenerics } from '../utils/tree'; + +import {test} from '@jest/globals'; + +const cases: Array<[string, string[]]> = [ + [ + 'Volo.Abp.Application.Dtos.AuditedEntityWithUserDto', + ['Volo.Abp.Application.Dtos.AuditedEntityWithUserDto'], + ], + [ + 'Volo.Abp.Application.Dtos.AuditedEntityWithUserDto', + ['Volo.Abp.Application.Dtos.AuditedEntityWithUserDto', 'Volo.Abp.Identity.IdentityUserDto'], + ], + [ + 'Volo.Abp.Application.Dtos.AuditedEntityWithUserDto', + [ + 'Volo.Abp.Application.Dtos.AuditedEntityWithUserDto', + 'string', + 'Volo.Abp.Identity.IdentityUserDto' + ], + ], + [ + 'Volo.Abp.Application.Dtos.AuditedEntityWithUserDto>', + [ + 'Volo.Abp.Application.Dtos.AuditedEntityWithUserDto', + 'string', + 'Volo.Abp.Identity.IdentityUserDto', + 'number', + ], + ], + [ + 'Volo.Abp.Application.Dtos.AuditedEntityWithUserDto>>', + [ + 'Volo.Abp.Application.Dtos.AuditedEntityWithUserDto', + 'string', + 'Volo.Abp.Identity.IdentityUserDto', + 'Volo.Abp.Core.Dummy', + 'System.String', + ], + ], + [ + 'AuditedEntityWithUserDto', + ['AuditedEntityWithUserDto'], + ], +]; + +test.each(cases)('should parse %s', (inputStr, expected) => { + const parsed = parseBaseTypeWithGenericTypes(inputStr); + expect(parsed).toEqual(expected); +}) + +describe('parseGenerics', () => { + + it('should work with simple type', function() { + const node = parseGenerics('System.String'); + expect(node.data).toEqual('System.String'); + expect(node.index).toBe(0); + expect(node.parent).toBe(null); + }); + it('should work with simple Array type', function() { + const node = parseGenerics('System.String[]'); + expect(node.data).toEqual('System.String[]'); + expect(node.index).toBe(0); + expect(node.parent).toBe(null); + }); + + it('should work with simple', function() { + const node = parseGenerics('Volo.Abp.Application.Dtos.AuditedEntityWithUserDto'); + expect(node.data).toEqual('Volo.Abp.Application.Dtos.AuditedEntityWithUserDto'); + expect(node.index).toBe(0); + expect(node.parent).toBe(null); + }); + + it('should work with `Volo.Abp.Application.Dtos.AuditedEntityWithUserDto`', function() { + const type = 'Volo.Abp.Application.Dtos.AuditedEntityWithUserDto'; + const node = parseGenerics(type); + + expect(node.data).toEqual('Volo.Abp.Application.Dtos.AuditedEntityWithUserDto'); + expect(node.children.length).toBe(1); + const child = node.children[0]; + expect(node.children[0].data).toEqual('Volo.Abp.Identity.IdentityUserDto'); + expect(child.parent).toBe(node); + }); + + + it('should work with `Volo.Abp.Application.Dtos.AuditedEntityWithUserDto`', function() { + const type = 'Volo.Abp.Application.Dtos.AuditedEntityWithUserDto'; + const node = parseGenerics(type); + + expect(node.data).toEqual('Volo.Abp.Application.Dtos.AuditedEntityWithUserDto'); + expect(node.children.length).toBe(2); + expect(node.children[0].data).toEqual('System.string'); + expect(node.children[0].index).toBe(0) + expect(node.children[1].data).toEqual('Volo.Abp.Identity.IdentityUserDto'); + expect(node.children[1].index).toBe(1); + + }); + it('should Volo.Abp.Application.Dtos.AuditedEntityWithUserDto>', function() { + const type = 'Volo.Abp.Application.Dtos.AuditedEntityWithUserDto>'; + const node = parseGenerics(type); + expect(node.data).toEqual('Volo.Abp.Application.Dtos.AuditedEntityWithUserDto'); + expect(node.children.length).toBe(2); + expect(node.children[0].data).toEqual('System.string'); + expect((node.children[0]).parent).toBe(node); + + expect(node.children[1].data).toEqual('Volo.Abp.Identity.IdentityUserDto'); + expect(node.children[1].children.length).toBe(1); + expect(node.children[1].children[0].data).toEqual('System.Int'); + expect(node.children[1].children[0].parent).toBe(node.children[1]) + expect(node.children[1].children[0].index).toBe(0) + + }); + + it('should Volo.Abp.Application.Dtos.AuditedEntityWithUserDto,System.string>', function() { + const type = 'Volo.Abp.Application.Dtos.AuditedEntityWithUserDto,System.string>'; + const node = parseGenerics(type); + expect(node.data).toEqual('Volo.Abp.Application.Dtos.AuditedEntityWithUserDto'); + expect(node.children.length).toBe(2); + expect(node.children[0].data).toEqual('Volo.Abp.Identity.IdentityUserDto'); + expect(node.children[0].children.length).toBe(1); + expect(node.children[0].children[0].data).toEqual('System.Int'); + expect(node.children[1].data).toEqual('System.string'); + + }); +}); + + + diff --git a/npm/ng-packs/packages/schematics/src/utils/model.ts b/npm/ng-packs/packages/schematics/src/utils/model.ts index 4ef8a4cb97..11ff88d15a 100644 --- a/npm/ng-packs/packages/schematics/src/utils/model.ts +++ b/npm/ng-packs/packages/schematics/src/utils/model.ts @@ -9,7 +9,7 @@ import { import { parseNamespace } from './namespace'; import { relativePathToModel } from './path'; import { camel } from './text'; -import { parseGenerics } from './tree'; +import { parseGenerics, TypeNode } from './tree'; import { createTypeParser, createTypeSimplifier, @@ -71,12 +71,16 @@ export function createImportRefsToModelReducer(params: ModelGeneratorParams) { model.interfaces.forEach(_interface => { const { baseType } = types[_interface.ref]; - if (baseType && parseNamespace(solution, baseType) !== model.namespace) - toBeImported.push({ - type: baseType.split('<')[0], - isEnum: false, - }); + if (baseType && parseNamespace(solution, baseType) !== model.namespace){ + const baseTypeWithGenericParams = parseBaseTypeWithGenericTypes(baseType); + baseTypeWithGenericParams.forEach(t => { + toBeImported.push({ + type: t, + isEnum: false, + }); + }) +} [..._interface.properties, ..._interface.generics].forEach(prop => { prop.refs.forEach(ref => { const propType = types[ref]; @@ -172,7 +176,20 @@ export function createRefToImportReducerCreator(params: ModelGeneratorParams) { } function isOptionalProperty(prop: PropertyDef) { - return ( - prop.typeSimple.endsWith('?') || (prop.typeSimple === 'string' && prop.isRequired === false) - ); + return (prop.typeSimple.endsWith('?') || (prop.typeSimple === 'string' && !prop.isRequired)); +} + +export function parseBaseTypeWithGenericTypes(type: string): string[] { + const parsedTypeNode = parseGenerics(type); + const nodeToText = (node: TypeNode,acc:string[] = []): string[] => { + + acc.push(node.data); + if(node.children && node.children.length > 0){ + node.children.forEach(child => { + nodeToText(child,acc); + }) + } + return acc; + } + return nodeToText(parsedTypeNode); } diff --git a/npm/ng-packs/packages/schematics/src/utils/tree.ts b/npm/ng-packs/packages/schematics/src/utils/tree.ts index 5fd8414f0c..489e0229fc 100644 --- a/npm/ng-packs/packages/schematics/src/utils/tree.ts +++ b/npm/ng-packs/packages/schematics/src/utils/tree.ts @@ -39,7 +39,7 @@ export class TypeNode { } } -export function parseGenerics(type: string, mapperFn?: TypeNodeMapperFn) { +export function parseGenericsOld(type: string, mapperFn?: TypeNodeMapperFn) { const [rootType, ...types] = type.split('<'); const root = new TypeNode(rootType, null, mapperFn); @@ -68,4 +68,33 @@ export function parseGenerics(type: string, mapperFn?: TypeNodeMapperFn) { return root; } +export function parseGenerics(type: string, mapperFn?: TypeNodeMapperFn, parent?: TypeNode | null): TypeNode { + const regex = /(?[\w.]+)<(?.*)>/; + + const match = type.match(regex); + if (!match) { + return new TypeNode(type, null, mapperFn); + } + + const mainType = match.groups?.MainType || ''; + const genericType = match.groups?.GenericType || ''; + const root = new TypeNode(mainType, parent ?? null, mapperFn); + if (genericType.includes(',')) { + const genericTypes = genericType.split(','); + genericTypes.forEach((genericType, index) => { + const child = parseGenerics(genericType, mapperFn, root); + child.index = index; + root.children.push(child); + child.parent = root; + }); + } else { + const child = parseGenerics(genericType, mapperFn, root); + child.index = root.children.length; + root.children.push(child); + child.parent = root; + } + return root; +} + + export type TypeNodeMapperFn = (node: TypeNode) => string;