@@ -2,22 +2,34 @@ import * as ts from 'typescript';
22import { GetDescriptor } from '../descriptor/descriptor' ;
33import { TypescriptHelper } from '../descriptor/helper/helper' ;
44import { TypescriptCreator } from '../helper/creator' ;
5- import { TransformerLogger } from '../logger/transformerLogger' ;
6- import { MockDefiner } from '../mockDefiner/mockDefiner' ;
75import { MockIdentifierGenericParameterIds , MockIdentifierGenericParameterValue } from '../mockIdentifier/mockIdentifier' ;
86import { Scope } from '../scope/scope' ;
97import { IGenericDeclaration } from './genericDeclaration.interface' ;
108import { GenericDeclarationSupported } from './genericDeclarationSupported' ;
119import { GenericParameter } from './genericParameter' ;
1210
11+ function isInstantiable ( node : ts . Declaration | undefined ) : boolean {
12+ let actualType : ts . Node | undefined = node ;
13+
14+ if ( ! actualType ) {
15+ return false ;
16+ }
17+
18+ while ( ts . isTypeAliasDeclaration ( actualType ) ) {
19+ actualType = actualType . type ;
20+ }
21+
22+ return ! TypescriptHelper . IsLiteralOrPrimitive ( actualType ) ;
23+ }
24+
1325export function GenericDeclaration ( scope : Scope ) : IGenericDeclaration {
1426 const generics : GenericParameter [ ] = [ ] ;
1527
1628 function isGenericProvided < T extends ts . TypeReferenceNode | ts . ExpressionWithTypeArguments > ( node : T , index : number ) : node is T & Required < ts . NodeWithTypeArguments > {
1729 return ! ! node . typeArguments && ! ! node . typeArguments [ index ] ;
1830 }
1931
20- function getGenericNode ( node : ts . TypeReferenceNode | ts . ExpressionWithTypeArguments , nodeDeclaration : ts . TypeParameterDeclaration , index : number ) : ts . Node {
32+ function getGenericNode ( node : ts . TypeReferenceNode | ts . ExpressionWithTypeArguments , nodeDeclaration : ts . TypeParameterDeclaration , index : number ) : ts . TypeNode {
2133 if ( isGenericProvided ( node , index ) ) {
2234 return node . typeArguments [ index ] ;
2335 }
@@ -40,11 +52,50 @@ export function GenericDeclaration(scope: Scope): IGenericDeclaration {
4052 }
4153 }
4254
43- function createGenericParameter ( ownerKey : string , nodeOwnerParameter : ts . TypeParameterDeclaration , genericDescriptor : ts . Expression ) : GenericParameter {
55+ function createGenericParameter ( ownerKey : string , nodeOwnerParameter : ts . TypeParameterDeclaration , genericDescriptor : ts . Expression | undefined , instantiable : boolean ) : GenericParameter {
4456 const uniqueName : string = ownerKey + nodeOwnerParameter . name . escapedText . toString ( ) ;
45- const genericFunction : ts . FunctionExpression = TypescriptCreator . createFunctionExpression ( ts . createBlock (
46- [ ts . createReturn ( genericDescriptor ) ] ,
47- ) ) ;
57+
58+ const genericValueDescriptor : ts . Expression = ( ( ) : ts . Expression => {
59+ if ( ! instantiable ) {
60+ return genericDescriptor || ts . createNull ( ) ;
61+ }
62+
63+ return ts . createNew (
64+ genericDescriptor ? TypescriptCreator . createFunctionExpression (
65+ ts . createBlock (
66+ [
67+ ts . createExpressionStatement (
68+ ts . createCall (
69+ ts . createPropertyAccess (
70+ ts . createIdentifier ( 'Object' ) ,
71+ ts . createIdentifier ( 'assign' ) ,
72+ ) ,
73+ undefined ,
74+ [
75+ ts . createIdentifier ( 'this' ) ,
76+ genericDescriptor ,
77+ ]
78+ ) ,
79+ ) ,
80+ ] ,
81+ ) ,
82+ ) : ts . createPropertyAccess (
83+ ts . createIdentifier ( 'this' ) ,
84+ ts . createIdentifier ( 'constructor' ) ,
85+ ) ,
86+ undefined ,
87+ undefined ,
88+ ) ;
89+ } ) ( ) ;
90+
91+ const genericFunction : ts . FunctionExpression =
92+ TypescriptCreator . createFunctionExpression (
93+ ts . createBlock ( [
94+ ts . createReturn (
95+ genericValueDescriptor ,
96+ ) ,
97+ ] ) ,
98+ ) ;
4899
49100 return {
50101 ids : [ uniqueName ] ,
@@ -54,9 +105,9 @@ export function GenericDeclaration(scope: Scope): IGenericDeclaration {
54105
55106 return {
56107 addFromTypeReferenceNode ( node : ts . TypeReferenceNode , declarationKey : string ) : void {
57- const typeParameterDeclarations : ts . NodeArray < ts . TypeParameterDeclaration > = TypescriptHelper . GetParameterOfNode ( node . typeName ) ;
108+ const typeParameterDeclarations : ts . NodeArray < ts . TypeParameterDeclaration > | undefined = TypescriptHelper . GetParameterOfNode ( node . typeName ) ;
58109
59- if ( ! typeParameterDeclarations ) {
110+ if ( ! typeParameterDeclarations ?. length ) {
60111 return ;
61112 }
62113
@@ -66,7 +117,9 @@ export function GenericDeclaration(scope: Scope): IGenericDeclaration {
66117 const genericParameter : GenericParameter = createGenericParameter (
67118 declarationKey ,
68119 typeParameterDeclarations [ index ] ,
69- GetDescriptor ( genericNode , scope ) ) ;
120+ GetDescriptor ( genericNode , scope ) ,
121+ false ,
122+ ) ;
70123
71124 generics . push ( genericParameter ) ;
72125 } ) ;
@@ -79,24 +132,18 @@ export function GenericDeclaration(scope: Scope): IGenericDeclaration {
79132 extension : ts . ExpressionWithTypeArguments ) : void {
80133 const extensionDeclarationTypeParameters : ts . NodeArray < ts . TypeParameterDeclaration > | undefined = extensionDeclaration . typeParameters ;
81134
82- if ( ! extensionDeclarationTypeParameters ) {
135+ if ( ! extensionDeclarationTypeParameters ?. length ) {
83136 return ;
84137 }
85138
86139 extensionDeclarationTypeParameters . reduce ( ( acc : GenericParameter [ ] , declaration : ts . TypeParameterDeclaration , index : number ) => {
87140 const genericNode : ts . Node = getGenericNode ( extension , declaration , index ) ;
88141
142+ let typeParameterDeclaration : ts . Declaration | undefined ;
143+ let genericValueDescriptor : ts . Expression | undefined ;
144+
89145 if ( ts . isTypeReferenceNode ( genericNode ) ) {
90- const typeParameterDeclaration : ts . Declaration = TypescriptHelper . GetDeclarationFromNode ( genericNode . typeName ) ;
91-
92- const isExtendingItself : boolean = MockDefiner . instance . getDeclarationKeyMap ( typeParameterDeclaration ) === declarationKey ;
93- if ( isExtendingItself ) {
94- // FIXME: Currently, circular generics aren't supported. See
95- // https://github.com/Typescript-TDD/ts-auto-mock/pull/312 for more
96- // details.
97- TransformerLogger ( ) . circularGenericNotSupported ( genericNode . getText ( ) ) ;
98- return acc ;
99- }
146+ typeParameterDeclaration = TypescriptHelper . GetDeclarationFromNode ( genericNode . typeName ) ;
100147
101148 if ( ts . isTypeParameterDeclaration ( typeParameterDeclaration ) ) {
102149 addGenericParameterToExisting (
@@ -110,10 +157,15 @@ export function GenericDeclaration(scope: Scope): IGenericDeclaration {
110157 }
111158 }
112159
160+ if ( ! typeParameterDeclaration || scope . currentMockKey !== declarationKey ) {
161+ genericValueDescriptor = GetDescriptor ( genericNode , new Scope ( declarationKey ) ) ;
162+ }
163+
113164 const genericParameter : GenericParameter = createGenericParameter (
114165 extensionDeclarationKey ,
115- extensionDeclarationTypeParameters [ index ] ,
116- GetDescriptor ( genericNode , scope ) ,
166+ declaration ,
167+ genericValueDescriptor ,
168+ isInstantiable ( typeParameterDeclaration ) ,
117169 ) ;
118170
119171 acc . push ( genericParameter ) ;
0 commit comments