@@ -2,22 +2,34 @@ import * as ts from 'typescript';
2
2
import { GetDescriptor } from '../descriptor/descriptor' ;
3
3
import { TypescriptHelper } from '../descriptor/helper/helper' ;
4
4
import { TypescriptCreator } from '../helper/creator' ;
5
- import { TransformerLogger } from '../logger/transformerLogger' ;
6
- import { MockDefiner } from '../mockDefiner/mockDefiner' ;
7
5
import { MockIdentifierGenericParameterIds , MockIdentifierGenericParameterValue } from '../mockIdentifier/mockIdentifier' ;
8
6
import { Scope } from '../scope/scope' ;
9
7
import { IGenericDeclaration } from './genericDeclaration.interface' ;
10
8
import { GenericDeclarationSupported } from './genericDeclarationSupported' ;
11
9
import { GenericParameter } from './genericParameter' ;
12
10
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
+
13
25
export function GenericDeclaration ( scope : Scope ) : IGenericDeclaration {
14
26
const generics : GenericParameter [ ] = [ ] ;
15
27
16
28
function isGenericProvided < T extends ts . TypeReferenceNode | ts . ExpressionWithTypeArguments > ( node : T , index : number ) : node is T & Required < ts . NodeWithTypeArguments > {
17
29
return ! ! node . typeArguments && ! ! node . typeArguments [ index ] ;
18
30
}
19
31
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 {
21
33
if ( isGenericProvided ( node , index ) ) {
22
34
return node . typeArguments [ index ] ;
23
35
}
@@ -40,11 +52,50 @@ export function GenericDeclaration(scope: Scope): IGenericDeclaration {
40
52
}
41
53
}
42
54
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 {
44
56
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
+ ) ;
48
99
49
100
return {
50
101
ids : [ uniqueName ] ,
@@ -54,9 +105,9 @@ export function GenericDeclaration(scope: Scope): IGenericDeclaration {
54
105
55
106
return {
56
107
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 ) ;
58
109
59
- if ( ! typeParameterDeclarations ) {
110
+ if ( ! typeParameterDeclarations ?. length ) {
60
111
return ;
61
112
}
62
113
@@ -66,7 +117,9 @@ export function GenericDeclaration(scope: Scope): IGenericDeclaration {
66
117
const genericParameter : GenericParameter = createGenericParameter (
67
118
declarationKey ,
68
119
typeParameterDeclarations [ index ] ,
69
- GetDescriptor ( genericNode , scope ) ) ;
120
+ GetDescriptor ( genericNode , scope ) ,
121
+ false ,
122
+ ) ;
70
123
71
124
generics . push ( genericParameter ) ;
72
125
} ) ;
@@ -79,24 +132,18 @@ export function GenericDeclaration(scope: Scope): IGenericDeclaration {
79
132
extension : ts . ExpressionWithTypeArguments ) : void {
80
133
const extensionDeclarationTypeParameters : ts . NodeArray < ts . TypeParameterDeclaration > | undefined = extensionDeclaration . typeParameters ;
81
134
82
- if ( ! extensionDeclarationTypeParameters ) {
135
+ if ( ! extensionDeclarationTypeParameters ?. length ) {
83
136
return ;
84
137
}
85
138
86
139
extensionDeclarationTypeParameters . reduce ( ( acc : GenericParameter [ ] , declaration : ts . TypeParameterDeclaration , index : number ) => {
87
140
const genericNode : ts . Node = getGenericNode ( extension , declaration , index ) ;
88
141
142
+ let typeParameterDeclaration : ts . Declaration | undefined ;
143
+ let genericValueDescriptor : ts . Expression | undefined ;
144
+
89
145
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 ) ;
100
147
101
148
if ( ts . isTypeParameterDeclaration ( typeParameterDeclaration ) ) {
102
149
addGenericParameterToExisting (
@@ -110,10 +157,15 @@ export function GenericDeclaration(scope: Scope): IGenericDeclaration {
110
157
}
111
158
}
112
159
160
+ if ( ! typeParameterDeclaration || scope . currentMockKey !== declarationKey ) {
161
+ genericValueDescriptor = GetDescriptor ( genericNode , new Scope ( declarationKey ) ) ;
162
+ }
163
+
113
164
const genericParameter : GenericParameter = createGenericParameter (
114
165
extensionDeclarationKey ,
115
- extensionDeclarationTypeParameters [ index ] ,
116
- GetDescriptor ( genericNode , scope ) ,
166
+ declaration ,
167
+ genericValueDescriptor ,
168
+ isInstantiable ( typeParameterDeclaration ) ,
117
169
) ;
118
170
119
171
acc . push ( genericParameter ) ;
0 commit comments