From a2baf3584ea7d9d263a058076eb8c18e911ddbfa Mon Sep 17 00:00:00 2001 From: Pmyl Date: Tue, 3 Dec 2019 19:30:06 +0000 Subject: [PATCH 1/4] feat(constructSignature): add construct signature --- docs/DETAILS.md | 22 +++++++ src/transformer/descriptor/descriptor.ts | 3 +- .../descriptor/method/functionType.ts | 2 +- .../descriptor/properties/properties.ts | 5 +- .../descriptor/methods/methods.test.ts | 62 +++++++++++++++++++ 5 files changed, 91 insertions(+), 3 deletions(-) diff --git a/docs/DETAILS.md b/docs/DETAILS.md index b4dc13927..80a732f2a 100644 --- a/docs/DETAILS.md +++ b/docs/DETAILS.md @@ -38,6 +38,28 @@ const mock = createMock(); mock() // 0 mock.name // "" +``` +## Interfaces with construct signatures +For overload constructors it will use the first one +```ts +interface PersonWithHat { + hatSize: number; +} + +interface PersonWithoutHat { + shirtSize: number; +} + +interface Person { + new (hatSize: number): PersonWithHat + new (): PersonWithoutHat + name: string +} + +const mock = createMock(); +new mock() // { hatSize: 0 } +mock.name // "" + ``` ## Classes ```ts diff --git a/src/transformer/descriptor/descriptor.ts b/src/transformer/descriptor/descriptor.ts index c89e11381..dc07dfac3 100644 --- a/src/transformer/descriptor/descriptor.ts +++ b/src/transformer/descriptor/descriptor.ts @@ -70,8 +70,9 @@ export function GetDescriptor(node: ts.Node, scope: Scope): ts.Expression { return GetMethodDeclarationDescriptor(node as ts.MethodDeclaration, scope); case ts.SyntaxKind.FunctionType: return GetFunctionTypeDescriptor(node as ts.FunctionTypeNode, scope); + case ts.SyntaxKind.ConstructSignature: case ts.SyntaxKind.CallSignature: - return GetFunctionTypeDescriptor(node as ts.CallSignatureDeclaration, scope); + return GetFunctionTypeDescriptor(node as ts.CallSignatureDeclaration | ts.ConstructSignatureDeclaration, scope); case ts.SyntaxKind.ArrowFunction: case ts.SyntaxKind.FunctionExpression: return GetFunctionAssignmentDescriptor(node as ts.ArrowFunction, scope); diff --git a/src/transformer/descriptor/method/functionType.ts b/src/transformer/descriptor/method/functionType.ts index f0e728dd8..28efabebb 100644 --- a/src/transformer/descriptor/method/functionType.ts +++ b/src/transformer/descriptor/method/functionType.ts @@ -4,7 +4,7 @@ import { GetDescriptor } from '../descriptor'; import { PropertySignatureCache } from '../property/cache'; import { GetMethodDescriptor } from './method'; -export function GetFunctionTypeDescriptor(node: ts.FunctionTypeNode | ts.CallSignatureDeclaration, scope: Scope): ts.Expression { +export function GetFunctionTypeDescriptor(node: ts.FunctionTypeNode | ts.CallSignatureDeclaration | ts.ConstructSignatureDeclaration, scope: Scope): ts.Expression { const property: ts.PropertyName = PropertySignatureCache.instance.get(); const returnValue: ts.Expression = GetDescriptor(node.type, scope); diff --git a/src/transformer/descriptor/properties/properties.ts b/src/transformer/descriptor/properties/properties.ts index e942bf4e8..007c9e443 100644 --- a/src/transformer/descriptor/properties/properties.ts +++ b/src/transformer/descriptor/properties/properties.ts @@ -9,7 +9,10 @@ export function GetProperties(node: ts.Node, scope: Scope): ts.Expression { const type: ts.Type = typeChecker.getTypeAtLocation(node); const symbols: ts.Symbol[] = typeChecker.getPropertiesOfType(type); - const signatures: ReadonlyArray = typeChecker.getSignaturesOfType(type, SignatureKind.Call); + // const signatures: ReadonlyArray = typeChecker.getSignaturesOfType(type, SignatureKind.Call); + let signatures: Array = []; + Array.prototype.push.apply(signatures, typeChecker.getSignaturesOfType(type, SignatureKind.Call)); + Array.prototype.push.apply(signatures, typeChecker.getSignaturesOfType(type, SignatureKind.Construct)); return GetMockPropertiesFromSymbol(symbols, signatures, scope); } diff --git a/test/transformer/descriptor/methods/methods.test.ts b/test/transformer/descriptor/methods/methods.test.ts index 19027ab1d..1bda01d21 100644 --- a/test/transformer/descriptor/methods/methods.test.ts +++ b/test/transformer/descriptor/methods/methods.test.ts @@ -88,6 +88,68 @@ describe('for methods', () => { }); }); + describe('for interface construct signature', () => { + interface InterfaceWithConstructSignature { + new (a: number): { a: number }; + b: string; + } + + interface InterfaceWithConstructSignatureReturn { + new (a: number): InterfaceWithConstructSignature; + b: string; + } + + interface InterfaceWithConstructSignatureOverload { + new (a: number): { a: number }; + new (b: string): { b: string }; + new (): { c: Date }; + } + + it('should set the constructor and properties', () => { + const properties: InterfaceWithConstructSignature = createMock(); + expect(new properties(2).a).toBe(0); + expect(properties.b).toBe(''); + }); + + it('should set the constructor with return value constructor', () => { + const properties: InterfaceWithConstructSignatureReturn = createMock(); + expect(new (new properties(2))(2).a).toBe(0); + expect(new properties(2).b).toBe(''); + expect(properties.b).toBe(''); + }); + + it('should use the first overload if any', () => { + const properties: InterfaceWithConstructSignatureOverload = createMock(); + //tslint:disable-next-line + expect((new properties() as any).a).toBe(0); + }); + }); + + describe('for interface construct signature', () => { + interface InterfaceWithCallSignature { + new (a: number): { a: number }; + b: string; + } + + interface InterfaceWithCallSignatureReturn { + new (a: number): InterfaceWithCallSignature; + b: string; + } + + it('should set the constructor and properties', () => { + const properties: InterfaceWithCallSignature = createMock(); + expect(new properties(2).a).toBe(0); + expect(properties.b).toBe(''); + }); + + it('should set the constructor with return value constructor', () => { + const properties: InterfaceWithCallSignatureReturn = createMock(); + expect(new (new properties(2))(2).a).toBe(0); + expect(new properties(2).b).toBe(''); + expect(properties.b).toBe(''); + }); + }); + describe('for declaration', () => { class MyClass { public method(): number { From c01aaa922bb2d3423d3879ded2c8d1ab68876d84 Mon Sep 17 00:00:00 2001 From: Pmyl Date: Tue, 3 Dec 2019 19:38:09 +0000 Subject: [PATCH 2/4] remove commented code --- src/transformer/descriptor/properties/properties.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/transformer/descriptor/properties/properties.ts b/src/transformer/descriptor/properties/properties.ts index 007c9e443..7771b1407 100644 --- a/src/transformer/descriptor/properties/properties.ts +++ b/src/transformer/descriptor/properties/properties.ts @@ -9,7 +9,6 @@ export function GetProperties(node: ts.Node, scope: Scope): ts.Expression { const type: ts.Type = typeChecker.getTypeAtLocation(node); const symbols: ts.Symbol[] = typeChecker.getPropertiesOfType(type); - // const signatures: ReadonlyArray = typeChecker.getSignaturesOfType(type, SignatureKind.Call); let signatures: Array = []; Array.prototype.push.apply(signatures, typeChecker.getSignaturesOfType(type, SignatureKind.Call)); Array.prototype.push.apply(signatures, typeChecker.getSignaturesOfType(type, SignatureKind.Construct)); From 3d7a4946f1439b91e0fccae0ae5ad651b3ff0461 Mon Sep 17 00:00:00 2001 From: Pmyl Date: Tue, 3 Dec 2019 19:38:59 +0000 Subject: [PATCH 3/4] use const instead of let --- src/transformer/descriptor/properties/properties.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/transformer/descriptor/properties/properties.ts b/src/transformer/descriptor/properties/properties.ts index 7771b1407..dec1fcab5 100644 --- a/src/transformer/descriptor/properties/properties.ts +++ b/src/transformer/descriptor/properties/properties.ts @@ -9,7 +9,7 @@ export function GetProperties(node: ts.Node, scope: Scope): ts.Expression { const type: ts.Type = typeChecker.getTypeAtLocation(node); const symbols: ts.Symbol[] = typeChecker.getPropertiesOfType(type); - let signatures: Array = []; + const signatures: Array = []; Array.prototype.push.apply(signatures, typeChecker.getSignaturesOfType(type, SignatureKind.Call)); Array.prototype.push.apply(signatures, typeChecker.getSignaturesOfType(type, SignatureKind.Construct)); From a3be7d49e2c64803c9f6cae7ffe47ce782cb3e23 Mon Sep 17 00:00:00 2001 From: Pmyl Date: Tue, 3 Dec 2019 19:49:53 +0000 Subject: [PATCH 4/4] divide two cases for call and construct signature in the switch --- src/transformer/descriptor/descriptor.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/transformer/descriptor/descriptor.ts b/src/transformer/descriptor/descriptor.ts index dc07dfac3..d4d5e2a68 100644 --- a/src/transformer/descriptor/descriptor.ts +++ b/src/transformer/descriptor/descriptor.ts @@ -71,8 +71,9 @@ export function GetDescriptor(node: ts.Node, scope: Scope): ts.Expression { case ts.SyntaxKind.FunctionType: return GetFunctionTypeDescriptor(node as ts.FunctionTypeNode, scope); case ts.SyntaxKind.ConstructSignature: + return GetFunctionTypeDescriptor(node as ts.ConstructSignatureDeclaration, scope); case ts.SyntaxKind.CallSignature: - return GetFunctionTypeDescriptor(node as ts.CallSignatureDeclaration | ts.ConstructSignatureDeclaration, scope); + return GetFunctionTypeDescriptor(node as ts.CallSignatureDeclaration, scope); case ts.SyntaxKind.ArrowFunction: case ts.SyntaxKind.FunctionExpression: return GetFunctionAssignmentDescriptor(node as ts.ArrowFunction, scope);