import type * as ts from 'typescript' ; import { GetDescriptor } from '../descriptor/descriptor' ; import { TypescriptHelper } from '../descriptor/helper/helper' ; import { TransformerLogger } from '../logger/transformerLogger' ; import { MockDefiner } from '../mockDefiner/mockDefiner' ; import { Identifiers } from '../mockIdentifier/mockIdentifier' ; import { Scope } from '../scope/scope' ; import { createArrayLiteral , createBlock , createFunctionExpression , createObjectLiteral , createPropertyAssignment , createReturnStatement , createStringLiteral , } from '../../typescriptFactory/typescriptFactory' ; import { core } from '../core/core' ; import { IGenericDeclaration } from './genericDeclaration.interface' ; import { GenericDeclarationSupported } from './genericDeclarationSupported' ; import { GenericParameter } from './genericParameter' ; export function GenericDeclaration ( scope ) { const generics = [ ] ; function isGenericProvided < T extends ts . TypeReferenceNode | ts . ExpressionWithTypeArguments > ( node , index ) { return ! ! node . typeArguments && ! ! node . typeArguments [ index ] ; } function getGenericNode ( node , nodeDeclaration , index ) { if ( isGenericProvided ( node , index ) ) { return node . typeArguments [ index ] ; } return nodeDeclaration . default || core . ts . factory . createNull ( ) ; } function addGenericParameterToExisting ( ownerParameterDeclaration , typeParameterDeclaration , declarationKey , extensionDeclarationKey ) { const existingUniqueName = declarationKey + typeParameterDeclaration . name . escapedText . toString ( ) ; const uniqueName = extensionDeclarationKey + ownerParameterDeclaration . name . escapedText . toString ( ) ; const parameterToAdd = generics . find ( ( genericParameter ) => genericParameter . ids . includes ( existingUniqueName ) ) ; if ( parameterToAdd ?. ids ) { parameterToAdd . ids . push ( uniqueName ) ; } } function createGenericParameter ( ownerKey , nodeOwnerParameter , genericDescriptor ) { const uniqueName = ownerKey + nodeOwnerParameter . name . escapedText . toString ( ) ; const genericFunction = createFunctionExpression ( createBlock ( [ createReturnStatement ( genericDescriptor ) ] ) ) ; return { ids : [ uniqueName ] , value : genericFunction , } ; } return { addFromTypeReferenceNode ( node , declarationKey ) { const typeParameterDeclarations = TypescriptHelper . GetParameterOfNode ( node . typeName ) ; if ( ! typeParameterDeclarations ) { return ; } typeParameterDeclarations . forEach ( ( declaration , index ) => { const genericNode = getGenericNode ( node , declaration , index ) ; const genericParameter = createGenericParameter ( declarationKey , typeParameterDeclarations [ index ] , GetDescriptor ( genericNode , scope ) ) ; generics . push ( genericParameter ) ; } ) ; } , addFromDeclarationExtension ( declarationKey , extensionDeclaration , extensionDeclarationKey , extension ) { const extensionDeclarationTypeParameters = extensionDeclaration . typeParameters ; if ( ! extensionDeclarationTypeParameters ) { return ; } extensionDeclarationTypeParameters . reduce ( ( acc , declaration , index ) => { const genericNode = getGenericNode ( extension , declaration , index ) ; if ( core . ts . isTypeReferenceNode ( genericNode ) ) { const typeParameterDeclaration = TypescriptHelper . GetDeclarationFromNode ( genericNode . typeName ) ; const typeParameterDeclarationKey = MockDefiner . instance . getDeclarationKeyMapBasedOnScope ( typeParameterDeclaration , scope ) ; const isExtendingItself = typeParameterDeclarationKey === declarationKey ; if ( isExtendingItself ) { TransformerLogger ( ) . circularGenericNotSupported ( genericNode . getText ( ) ) ; return acc ; } if ( core . ts . isTypeParameterDeclaration ( typeParameterDeclaration ) ) { addGenericParameterToExisting ( extensionDeclarationTypeParameters [ index ] , typeParameterDeclaration , declarationKey , extensionDeclarationKey ) ; return acc ; } } const genericParameter = createGenericParameter ( extensionDeclarationKey , extensionDeclarationTypeParameters [ index ] , GetDescriptor ( genericNode , scope ) ) ; acc . push ( genericParameter ) ; return acc ; } , generics ) ; } , getExpressionForAllGenerics ( ) { return generics . map ( ( s ) => createObjectLiteral ( [ createPropertyAssignment ( Identifiers . MockIdentifierGenericParameterIds , createArrayLiteral ( s . ids . map ( ( arr ) => createStringLiteral ( arr ) ) , false ) ) , createPropertyAssignment ( Identifiers . MockIdentifierGenericParameterValue , s . value ) , ] , true ) ) ; } , } ; }