diff --git a/npm/ng-packs/packages/schematics/src/utils/model.ts b/npm/ng-packs/packages/schematics/src/utils/model.ts index fc8dde37c1..49d3c0fcf5 100644 --- a/npm/ng-packs/packages/schematics/src/utils/model.ts +++ b/npm/ng-packs/packages/schematics/src/utils/model.ts @@ -1,5 +1,11 @@ -import { VOLO_NAME_VALUE, VOLO_REGEX } from '../constants'; +import { VOLO_REGEX } from '../constants'; import { Interface, Model, Property, PropertyDef, Type, TypeWithEnum } from '../models'; +import { + extractGenerics, + generateRefWithPlaceholders, + GenericsCollector, + replacePlaceholdersWithGenerics, +} from './generics'; import { parseNamespace } from './namespace'; import { relativePathToModel } from './path'; import { camel } from './text'; @@ -8,6 +14,7 @@ import { createTypeParser, createTypeSimplifier, createTypesToImportsReducer, + extendsSelf, removeTypeModifiers, } from './type'; @@ -27,6 +34,7 @@ export function createImportRefsToModelReducer(params: ModelGeneratorParams) { return (models: Model[], importRefs: string[]) => { const enums: string[] = []; const interfaces = importRefs.reduce(reduceImportRefsToInterfaces, []); + sortInterfaces(interfaces); interfaces.forEach(_interface => { @@ -40,12 +48,9 @@ export function createImportRefsToModelReducer(params: ModelGeneratorParams) { const index = models.findIndex(m => m.namespace === _interface.namespace); if (index > -1) { if (models[index].interfaces.some(i => i.identifier === _interface.identifier)) return; - if (_interface.ref.startsWith(VOLO_NAME_VALUE.ref)) return; models[index].interfaces.push(_interface); } else { - if (_interface.ref.startsWith(VOLO_NAME_VALUE.ref)) _interface = VOLO_NAME_VALUE; - const { namespace } = _interface; models.push( @@ -70,7 +75,7 @@ export function createImportRefsToModelReducer(params: ModelGeneratorParams) { isEnum: false, }); - _interface.properties.forEach(prop => { + [..._interface.properties, ..._interface.generics].forEach(prop => { prop.refs.forEach(ref => { const propType = types[ref]; if (!propType) return; @@ -100,38 +105,50 @@ export function createImportRefToInterfaceReducerCreator(params: ModelGeneratorP const parseType = createTypeParser(removeTypeModifiers); const simplifyType = createTypeSimplifier(); const getIdentifier = (type: string) => removeTypeModifiers(simplifyType(type)); + const genericsCollector = new GenericsCollector(getIdentifier); return reduceRefsToInterfaces; - function reduceRefsToInterfaces(interfaces: Interface[], ref: string) { + function reduceRefsToInterfaces(interfaces: Interface[], ref: string): Interface[] { const typeDef = types[ref]; if (!typeDef) return interfaces; const namespace = parseNamespace(solution, ref); - const identifier = (typeDef.genericArguments ?? []).reduce( - (acc, t, i) => acc.replace(`T${i}`, t), - getIdentifier(ref), - ); + let { baseType: base, genericArguments } = typeDef; + genericArguments = genericArguments || []; + let identifier = getIdentifier(ref); + identifier = replacePlaceholdersWithGenerics(identifier, genericArguments, genericsCollector); + + if (base) { + if (extendsSelf(ref, base)) { + genericsCollector.collect(extractGenerics(base).generics, genericArguments); + return reduceRefsToInterfaces(interfaces, generateRefWithPlaceholders(base)); + } else { + base = getIdentifier(base); + } + } - const base = typeDef.baseType ? getIdentifier(typeDef.baseType) : null; - const _interface = new Interface({ identifier, base, namespace, ref }); + const { generics } = genericsCollector; + const _interface = new Interface({ identifier, base, namespace, ref, generics }); + genericsCollector.reset(); typeDef.properties?.forEach(prop => { const name = camel(prop.name); - const optional = isOptionalProperty(prop) ? '?' : ''; const type = simplifyType(prop.typeSimple); const refs = parseType(prop.type).reduce( (acc: string[], r) => acc.concat(parseGenerics(r).toGenerics()), [], ); + const property = new Property({ name, type, refs }); + property.setOptional(isOptionalProperty(prop)); - _interface.properties.push(new Property({ name, optional, type, refs })); + _interface.properties.push(property); }); interfaces.push(_interface); - return _interface.properties + return [..._interface.properties, ..._interface.generics] .reduce((refs, prop) => { prop.refs.forEach(type => { if (types[type]?.isEnum) return; @@ -142,7 +159,7 @@ export function createImportRefToInterfaceReducerCreator(params: ModelGeneratorP return refs; }, []) .concat(base ? parseGenerics(typeDef.baseType!).toGenerics() : []) - .reduce(reduceRefsToInterfaces, interfaces); + .reduce(reduceRefsToInterfaces, interfaces); } }