11import ts from 'typescript' ;
2- import { GetTsAutoMockOverloadOptions , TsAutoMockOverloadOptions } from '../../../options/overload' ;
3- import { TypescriptCreator } from '../../helper/creator' ;
2+ import { MethodSignature , TypescriptCreator } from '../../helper/creator' ;
43import { MockDefiner } from '../../mockDefiner/mockDefiner' ;
54import { ModuleName } from '../../mockDefiner/modules/moduleName' ;
5+ import { Scope } from '../../scope/scope' ;
6+ import { ResolveSignatureElseBranch } from '../helper/branching' ;
67import { TypescriptHelper } from '../helper/helper' ;
78
8- export interface MethodSignature {
9- parameters ?: ts . ParameterDeclaration [ ] ;
10- returnValue : ts . Expression ;
11- }
12-
13- export function GetMethodDescriptor ( propertyName : ts . PropertyName , methodSignatures : MethodSignature [ ] ) : ts . CallExpression {
9+ export function GetMethodDescriptor ( _propertyName : ts . PropertyName , methodSignatures : MethodSignature [ ] , scope : Scope ) : ts . CallExpression {
1410 const providerGetMethod : ts . PropertyAccessExpression = CreateProviderGetMethod ( ) ;
1511
16- const propertyNameString : string = TypescriptHelper . GetStringPropertyName ( propertyName ) ;
17- const propertyNameStringLiteral : ts . StringLiteral = ts . createStringLiteral ( propertyNameString ) ;
18-
1912 const signatureWithMostParameters : MethodSignature = methodSignatures . reduce (
2013 ( acc : MethodSignature , signature : MethodSignature ) => {
2114 const longestParametersLength : number = ( acc . parameters || [ ] ) . length ;
@@ -25,23 +18,21 @@ export function GetMethodDescriptor(propertyName: ts.PropertyName, methodSignatu
2518 } ,
2619 ) ;
2720
28- const longestParameterList : ts . ParameterDeclaration [ ] = signatureWithMostParameters . parameters || [ ] ;
29-
30- const declarationVariableMap : Map < ts . ParameterDeclaration , ts . Identifier > = new Map < ts . ParameterDeclaration , ts . Identifier > ( ) ;
21+ const declarationVariableMap : Map < ts . TypeNode , ts . Identifier > = new Map < ts . TypeNode , ts . Identifier > ( ) ;
3122
3223 let i : number = 0 ;
3324 const declarationVariables : ts . VariableDeclaration [ ] = methodSignatures . reduce (
34- ( variables : ts . VariableDeclaration [ ] , { parameters = [ ] } : MethodSignature ) => {
25+ ( variables : ts . VariableDeclaration [ ] , { parameters } : MethodSignature ) => {
3526 for ( const parameter of parameters ) {
36- if ( declarationVariableMap . has ( parameter ) ) {
27+ if ( declarationVariableMap . has ( parameter . type ) ) {
3728 continue ;
3829 }
3930
4031 const declarationType : ts . TypeNode | undefined = parameter . type ;
4132 if ( declarationType && ts . isTypeReferenceNode ( declarationType ) ) {
42- const variableIdentifier : ts . Identifier = ts . createIdentifier ( `__ ${ i ++ } ` ) ;
33+ const variableIdentifier : ts . Identifier = ts . createIdentifier ( `___ ${ i ++ } ` ) ;
4334
44- declarationVariableMap . set ( parameter , variableIdentifier ) ;
35+ declarationVariableMap . set ( parameter . type , variableIdentifier ) ;
4536
4637 const declaration : ts . Declaration = TypescriptHelper . GetDeclarationFromNode ( declarationType . typeName ) ;
4738
@@ -63,131 +54,20 @@ export function GetMethodDescriptor(propertyName: ts.PropertyName, methodSignatu
6354 statements . push ( TypescriptCreator . createVariableStatement ( declarationVariables ) ) ;
6455 }
6556
66- statements . push ( ResolveSignatureElseBranch ( declarationVariableMap , methodSignatures , longestParameterList ) ) ;
57+ statements . push ( ResolveSignatureElseBranch ( declarationVariableMap , methodSignatures , signatureWithMostParameters , scope ) ) ;
6758
6859 const block : ts . Block = ts . createBlock ( statements , true ) ;
6960
7061 const propertyValueFunction : ts . ArrowFunction = TypescriptCreator . createArrowFunction (
7162 block ,
72- longestParameterList ,
73- ) ;
74-
75- return TypescriptCreator . createCall ( providerGetMethod , [ propertyNameStringLiteral , propertyValueFunction ] ) ;
76- }
77-
78- function CreateTypeEquality ( signatureType : ts . Identifier | ts . TypeNode | undefined , primaryDeclaration : ts . ParameterDeclaration ) : ts . Expression {
79- const identifier : ts . Identifier = ts . createIdentifier ( primaryDeclaration . name . getText ( ) ) ;
80-
81- if ( ! signatureType ) {
82- return ts . createPrefix (
83- ts . SyntaxKind . ExclamationToken ,
84- ts . createPrefix (
85- ts . SyntaxKind . ExclamationToken ,
86- identifier ,
87- ) ,
88- ) ;
89- }
90-
91- if ( TypescriptHelper . IsLiteralOrPrimitive ( signatureType ) ) {
92- return ts . createStrictEquality (
93- ts . createTypeOf ( identifier ) ,
94- signatureType ? ts . createStringLiteral ( signatureType . getText ( ) ) : ts . createVoidZero ( ) ,
95- ) ;
96- }
97-
98- if ( ts . isIdentifier ( signatureType ) ) {
99- return ts . createStrictEquality (
100- ts . createPropertyAccess ( identifier , '__factory' ) ,
101- signatureType ,
102- ) ;
103- }
104-
105- return ts . createBinary ( identifier , ts . SyntaxKind . InstanceOfKeyword , ts . createIdentifier ( 'Object' ) ) ;
106- }
107-
108- function CreateUnionTypeOfEquality ( signatureType : ts . Identifier | ts . TypeNode | undefined , primaryDeclaration : ts . ParameterDeclaration ) : ts . Expression {
109- const typeNodesAndVariableReferences : Array < ts . TypeNode | ts . Identifier > = [ ] ;
110-
111- if ( signatureType ) {
112- if ( ts . isTypeNode ( signatureType ) && ts . isUnionTypeNode ( signatureType ) ) {
113- typeNodesAndVariableReferences . push ( ...signatureType . types ) ;
114- } else {
115- typeNodesAndVariableReferences . push ( signatureType ) ;
116- }
117- }
118-
119- const [ firstType , ...remainingTypes ] : Array < ts . TypeNode | ts . Identifier > = typeNodesAndVariableReferences ;
120-
121- return remainingTypes . reduce (
122- ( prevStatement : ts . Expression , typeNode : ts . TypeNode ) =>
123- ts . createLogicalOr (
124- prevStatement ,
125- CreateTypeEquality ( typeNode , primaryDeclaration ) ,
126- ) ,
127- CreateTypeEquality ( firstType , primaryDeclaration ) ,
63+ signatureWithMostParameters . parameters ,
12864 ) ;
129- }
13065
131- function ResolveParameterBranch (
132- declarationVariableMap : Map < ts . ParameterDeclaration , ts . Identifier > ,
133- declarations : ts . ParameterDeclaration [ ] ,
134- allDeclarations : ts . ParameterDeclaration [ ] ,
135- returnValue : ts . Expression ,
136- elseBranch : ts . Statement ,
137- ) : ts . Statement {
138- const [ firstDeclaration , ...remainingDeclarations ] : Array < ts . ParameterDeclaration | undefined > = declarations ;
139-
140- const variableReferenceOrType : ( declaration : ts . ParameterDeclaration ) => ts . Identifier | ts . TypeNode | undefined =
141- ( declaration : ts . ParameterDeclaration ) => {
142- if ( declarationVariableMap . has ( declaration ) ) {
143- return declarationVariableMap . get ( declaration ) ;
144- } else {
145- return declaration . type ;
146- }
147- } ;
148-
149- // TODO: These conditions quickly grow in size, but it should be possible to
150- // squeeze things together and optimize it with something like:
151- //
152- // const typeOf = function (left, right) { return typeof left === right; }
153- // const evaluate = (function(left, right) { return this._ = this._ || typeOf(left, right); }).bind({})
154- //
155- // if (evaluate(firstArg, 'boolean') && evaluate(secondArg, 'number') && ...) {
156- // ...
157- // }
158- //
159- // `this._' acts as a cache, since the control flow may evaluate the same
160- // conditions multiple times.
161- const condition : ts . Expression = remainingDeclarations . reduce (
162- ( prevStatement : ts . Expression , declaration : ts . ParameterDeclaration , index : number ) =>
163- ts . createLogicalAnd (
164- prevStatement ,
165- CreateUnionTypeOfEquality ( variableReferenceOrType ( declaration ) , allDeclarations [ index + 1 ] ) ,
166- ) ,
167- CreateUnionTypeOfEquality ( variableReferenceOrType ( firstDeclaration ) , allDeclarations [ 0 ] ) ,
66+ const propName : ts . StringLiteral = ts . createStringLiteral (
67+ TypescriptCreator . createSignatureHash ( methodSignatures ) ,
16868 ) ;
16969
170- return ts . createIf ( condition , ts . createReturn ( returnValue ) , elseBranch ) ;
171- }
172-
173- export function ResolveSignatureElseBranch (
174- declarationVariableMap : Map < ts . ParameterDeclaration , ts . Identifier > ,
175- signatures : MethodSignature [ ] ,
176- longestParameterList : ts . ParameterDeclaration [ ] ,
177- ) : ts . Statement {
178- const transformOverloadsOption : TsAutoMockOverloadOptions = GetTsAutoMockOverloadOptions ( ) ;
179-
180- const [ signature , ...remainingSignatures ] : MethodSignature [ ] = signatures . filter ( ( _ : unknown , notFirst : number ) => transformOverloadsOption || ! notFirst ) ;
181-
182- const indistinctSignatures : boolean = signatures . every ( ( sig : MethodSignature ) => ! sig . parameters ?. length ) ;
183- if ( ! remainingSignatures . length || indistinctSignatures ) {
184- return ts . createReturn ( signature . returnValue ) ;
185- }
186-
187- const elseBranch : ts . Statement = ResolveSignatureElseBranch ( declarationVariableMap , remainingSignatures , longestParameterList ) ;
188-
189- const currentParameters : ts . ParameterDeclaration [ ] = signature . parameters || [ ] ;
190- return ResolveParameterBranch ( declarationVariableMap , currentParameters , longestParameterList , signature . returnValue , elseBranch ) ;
70+ return TypescriptCreator . createCall ( providerGetMethod , [ propName , propertyValueFunction ] ) ;
19171}
19272
19373function CreateProviderGetMethod ( ) : ts . PropertyAccessExpression {
@@ -198,5 +78,6 @@ function CreateProviderGetMethod(): ts.PropertyAccessExpression {
19878 ts . createIdentifier ( 'Provider' ) ,
19979 ) ,
20080 ts . createIdentifier ( 'instance' ) ) ,
201- ts . createIdentifier ( 'getMethod' ) ) ;
81+ ts . createIdentifier ( 'getMethod' ) ,
82+ ) ;
20283}
0 commit comments