Skip to content

Commit

Permalink
feat(map): add Map support as a type (#228)
Browse files Browse the repository at this point in the history
* #225 add Map support as a type

Also changed a linting rule for indentation, remove some code regarding typescript types, fixed a bug when using typeof variable without type and function call initializer and removed descriptor 'case' for function call

* remove extra webpack configuration

* use custom function to get null descriptor

* remove casting, use typescript function to narrow type

* handle callExpression in descriptor, handle calls of variables
  • Loading branch information
Pmyl committed Feb 8, 2020
1 parent c9a45a1 commit 3006c84
Show file tree
Hide file tree
Showing 22 changed files with 456 additions and 247 deletions.
3 changes: 2 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@
},
"FunctionExpression": {
"parameters": "first"
}
},
"SwitchCase": 1
}
],
"@typescript-eslint/interface-name-prefix": "off",
Expand Down
36 changes: 36 additions & 0 deletions src/transformer/descriptor/callExpression/callExpression.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { FunctionLikeDeclaration } from 'typescript';
import * as ts from 'typescript';
import { TransformerLogger } from '../../logger/transformerLogger';
import { NodeToString } from '../../printNode';
import { Scope } from '../../scope/scope';
import { GetDescriptor } from '../descriptor';
import { TypescriptHelper } from '../helper/helper';
import { GetFunctionReturnType } from '../method/functionReturnType';
import { GetNullDescriptor } from '../null/null';

export function GetCallExpressionDescriptor(node: ts.CallExpression, scope: Scope): ts.Expression {
return GetDescriptor(GetCallExpressionType(node), scope);
}

export function GetCallExpressionType(node: ts.CallExpression): ts.Node {
const declaration: ts.Declaration = TypescriptHelper.GetDeclarationFromNode(node.expression);

return GetFinalFunctionTypeFromDeclaration(node, declaration);
}

function GetFinalFunctionTypeFromDeclaration(initialNode: ts.Node, node: ts.Node): ts.Node {
if (ts.isFunctionLike(node)) {
return GetFunctionReturnType(node as FunctionLikeDeclaration);
} else if (ts.isVariableDeclaration(node)) {
if (node.type) {
if (ts.isFunctionTypeNode(node.type)) {
return node.type.type;
}
} else if (node.initializer) {
return GetFinalFunctionTypeFromDeclaration(initialNode, node.initializer);
}
}

TransformerLogger().typeOfFunctionCallNotFound(NodeToString(initialNode));
return GetNullDescriptor();
}
199 changes: 100 additions & 99 deletions src/transformer/descriptor/descriptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { GetBigIntDescriptor } from './bigint/bigint';
import { GetBooleanDescriptor } from './boolean/boolean';
import { GetBooleanFalseDescriptor } from './boolean/booleanFalse';
import { GetBooleanTrueDescriptor } from './boolean/booleanTrue';
import { GetCallExpressionDescriptor } from './callExpression/callExpression';
import { GetClassDeclarationDescriptor } from './class/classDeclaration';
import { GetConstructorTypeDescriptor } from './constructor/constructorType';
import { GetEnumDeclarationDescriptor } from './enum/enumDeclaration';
Expand Down Expand Up @@ -40,104 +41,104 @@ import { GetUnionDescriptor } from './union/union';

export function GetDescriptor(node: ts.Node, scope: Scope): ts.Expression {
switch (node.kind) {
case ts.SyntaxKind.TypeAliasDeclaration:
return GetTypeAliasDescriptor(node as ts.TypeAliasDeclaration, scope);
case ts.SyntaxKind.TypeReference:
return GetTypeReferenceDescriptor(node as ts.TypeReferenceNode, scope);
case ts.SyntaxKind.TypeLiteral:
return GetTypeLiteralDescriptor(node as ts.TypeLiteralNode, scope);
case ts.SyntaxKind.InterfaceDeclaration:
return GetInterfaceDeclarationDescriptor(node as ts.InterfaceDeclaration, scope);
case ts.SyntaxKind.ClassDeclaration:
return GetClassDeclarationDescriptor(node as ts.ClassDeclaration, scope);
case ts.SyntaxKind.PropertySignature:
case ts.SyntaxKind.PropertyAssignment:
return GetPropertyDescriptor(node as ts.PropertySignature, scope);
case ts.SyntaxKind.PropertyDeclaration:
return GetPropertyDescriptor(node as ts.PropertyDeclaration, scope);
case ts.SyntaxKind.LiteralType:
return GetLiteralDescriptor(node as ts.LiteralTypeNode, scope);
case ts.SyntaxKind.ExpressionWithTypeArguments:
return GetExpressionWithTypeArgumentsDescriptor(node as ts.ExpressionWithTypeArguments, scope);
case ts.SyntaxKind.Identifier:
return GetIdentifierDescriptor(node as ts.Identifier, scope);
case ts.SyntaxKind.ThisType:
return GetMockFactoryCallForThis(scope.currentMockKey);
case ts.SyntaxKind.ImportSpecifier:
return GetImportDescriptor(node as ts.ImportSpecifier, scope);
case ts.SyntaxKind.TypeParameter:
return GetTypeParameterDescriptor(node as ts.TypeParameterDeclaration, scope);
case ts.SyntaxKind.ImportClause:
return GetImportDescriptor(node as ts.ImportClause, scope);
case ts.SyntaxKind.MethodSignature:
return GetMethodSignatureDescriptor(node as ts.MethodSignature, scope);
case ts.SyntaxKind.FunctionDeclaration:
return GetMethodDeclarationDescriptor(node as ts.FunctionDeclaration, scope);
case ts.SyntaxKind.MethodDeclaration:
return GetMethodDeclarationDescriptor(node as ts.MethodDeclaration, scope);
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, scope);
case ts.SyntaxKind.ArrowFunction:
case ts.SyntaxKind.FunctionExpression:
return GetFunctionAssignmentDescriptor(node as ts.ArrowFunction, scope);
case ts.SyntaxKind.ConstructorType:
return GetConstructorTypeDescriptor(node as ts.ConstructorTypeNode, scope);
case ts.SyntaxKind.TypeQuery:
return GetTypeQueryDescriptor(node as ts.TypeQueryNode, scope);
case ts.SyntaxKind.UnionType:
return GetUnionDescriptor(node as ts.UnionTypeNode, scope);
case ts.SyntaxKind.IntersectionType:
return GetIntersectionDescriptor(node as ts.IntersectionTypeNode, scope);
case ts.SyntaxKind.EnumDeclaration:
return GetEnumDeclarationDescriptor(node as ts.EnumDeclaration);
case ts.SyntaxKind.MappedType:
return GetMappedDescriptor(node as ts.MappedTypeNode, scope);
case ts.SyntaxKind.ParenthesizedType:
return GetParenthesizedDescriptor(node as ts.ParenthesizedTypeNode, scope);
case ts.SyntaxKind.ArrayType:
case ts.SyntaxKind.TupleType:
return GetArrayDescriptor();
case ts.SyntaxKind.StringKeyword:
return GetStringDescriptor();
case ts.SyntaxKind.NumberKeyword:
return GetNumberDescriptor();
case ts.SyntaxKind.TrueKeyword:
return GetBooleanTrueDescriptor();
case ts.SyntaxKind.FalseKeyword:
return GetBooleanFalseDescriptor();
case ts.SyntaxKind.NumericLiteral:
case ts.SyntaxKind.StringLiteral:
return GetLiteralDescriptor(node as ts.LiteralTypeNode, scope);
case ts.SyntaxKind.ObjectLiteralExpression:
return GetObjectLiteralDescriptor(node as ts.ObjectLiteralExpression, scope);
case ts.SyntaxKind.IndexedAccessType:
return GetIndexedAccessTypeDescriptor(node as ts.IndexedAccessTypeNode, scope);
case ts.SyntaxKind.BooleanKeyword:
case ts.SyntaxKind.TypePredicate:
case ts.SyntaxKind.FirstTypeNode:
return GetBooleanDescriptor();
case ts.SyntaxKind.ObjectKeyword:
return GetMockPropertiesFromSymbol([], [], scope);
case ts.SyntaxKind.NullKeyword:
return GetNullDescriptor();
case ts.SyntaxKind.ImportEqualsDeclaration:
return GetImportEqualsDescriptor(node as ts.ImportEqualsDeclaration, scope);
case ts.SyntaxKind.BigIntKeyword:
return GetBigIntDescriptor();
case ts.SyntaxKind.AnyKeyword:
case ts.SyntaxKind.NeverKeyword:
case ts.SyntaxKind.UnknownKeyword:
case ts.SyntaxKind.UndefinedKeyword:
case ts.SyntaxKind.VoidKeyword:
return GetUndefinedDescriptor();
case ts.SyntaxKind.CallExpression:
return node as ts.CallExpression;
default:
TransformerLogger().typeNotSupported(ts.SyntaxKind[node.kind]);
return GetNullDescriptor();
case ts.SyntaxKind.TypeAliasDeclaration:
return GetTypeAliasDescriptor(node as ts.TypeAliasDeclaration, scope);
case ts.SyntaxKind.TypeReference:
return GetTypeReferenceDescriptor(node as ts.TypeReferenceNode, scope);
case ts.SyntaxKind.TypeLiteral:
return GetTypeLiteralDescriptor(node as ts.TypeLiteralNode, scope);
case ts.SyntaxKind.InterfaceDeclaration:
return GetInterfaceDeclarationDescriptor(node as ts.InterfaceDeclaration, scope);
case ts.SyntaxKind.ClassDeclaration:
return GetClassDeclarationDescriptor(node as ts.ClassDeclaration, scope);
case ts.SyntaxKind.PropertySignature:
case ts.SyntaxKind.PropertyAssignment:
return GetPropertyDescriptor(node as ts.PropertySignature, scope);
case ts.SyntaxKind.PropertyDeclaration:
return GetPropertyDescriptor(node as ts.PropertyDeclaration, scope);
case ts.SyntaxKind.LiteralType:
return GetLiteralDescriptor(node as ts.LiteralTypeNode, scope);
case ts.SyntaxKind.ExpressionWithTypeArguments:
return GetExpressionWithTypeArgumentsDescriptor(node as ts.ExpressionWithTypeArguments, scope);
case ts.SyntaxKind.Identifier:
return GetIdentifierDescriptor(node as ts.Identifier, scope);
case ts.SyntaxKind.ThisType:
return GetMockFactoryCallForThis(scope.currentMockKey);
case ts.SyntaxKind.ImportSpecifier:
return GetImportDescriptor(node as ts.ImportSpecifier, scope);
case ts.SyntaxKind.TypeParameter:
return GetTypeParameterDescriptor(node as ts.TypeParameterDeclaration, scope);
case ts.SyntaxKind.ImportClause:
return GetImportDescriptor(node as ts.ImportClause, scope);
case ts.SyntaxKind.MethodSignature:
return GetMethodSignatureDescriptor(node as ts.MethodSignature, scope);
case ts.SyntaxKind.FunctionDeclaration:
return GetMethodDeclarationDescriptor(node as ts.FunctionDeclaration, scope);
case ts.SyntaxKind.MethodDeclaration:
return GetMethodDeclarationDescriptor(node as ts.MethodDeclaration, scope);
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, scope);
case ts.SyntaxKind.ArrowFunction:
case ts.SyntaxKind.FunctionExpression:
return GetFunctionAssignmentDescriptor(node as ts.ArrowFunction, scope);
case ts.SyntaxKind.ConstructorType:
return GetConstructorTypeDescriptor(node as ts.ConstructorTypeNode, scope);
case ts.SyntaxKind.TypeQuery:
return GetTypeQueryDescriptor(node as ts.TypeQueryNode, scope);
case ts.SyntaxKind.UnionType:
return GetUnionDescriptor(node as ts.UnionTypeNode, scope);
case ts.SyntaxKind.IntersectionType:
return GetIntersectionDescriptor(node as ts.IntersectionTypeNode, scope);
case ts.SyntaxKind.EnumDeclaration:
return GetEnumDeclarationDescriptor(node as ts.EnumDeclaration);
case ts.SyntaxKind.MappedType:
return GetMappedDescriptor(node as ts.MappedTypeNode, scope);
case ts.SyntaxKind.ParenthesizedType:
return GetParenthesizedDescriptor(node as ts.ParenthesizedTypeNode, scope);
case ts.SyntaxKind.ArrayType:
case ts.SyntaxKind.TupleType:
return GetArrayDescriptor();
case ts.SyntaxKind.StringKeyword:
return GetStringDescriptor();
case ts.SyntaxKind.NumberKeyword:
return GetNumberDescriptor();
case ts.SyntaxKind.TrueKeyword:
return GetBooleanTrueDescriptor();
case ts.SyntaxKind.FalseKeyword:
return GetBooleanFalseDescriptor();
case ts.SyntaxKind.NumericLiteral:
case ts.SyntaxKind.StringLiteral:
return GetLiteralDescriptor(node as ts.LiteralTypeNode, scope);
case ts.SyntaxKind.ObjectLiteralExpression:
return GetObjectLiteralDescriptor(node as ts.ObjectLiteralExpression, scope);
case ts.SyntaxKind.IndexedAccessType:
return GetIndexedAccessTypeDescriptor(node as ts.IndexedAccessTypeNode, scope);
case ts.SyntaxKind.BooleanKeyword:
case ts.SyntaxKind.TypePredicate:
case ts.SyntaxKind.FirstTypeNode:
return GetBooleanDescriptor();
case ts.SyntaxKind.ObjectKeyword:
return GetMockPropertiesFromSymbol([], [], scope);
case ts.SyntaxKind.NullKeyword:
return GetNullDescriptor();
case ts.SyntaxKind.ImportEqualsDeclaration:
return GetImportEqualsDescriptor(node as ts.ImportEqualsDeclaration, scope);
case ts.SyntaxKind.BigIntKeyword:
return GetBigIntDescriptor();
case ts.SyntaxKind.AnyKeyword:
case ts.SyntaxKind.NeverKeyword:
case ts.SyntaxKind.UnknownKeyword:
case ts.SyntaxKind.UndefinedKeyword:
case ts.SyntaxKind.VoidKeyword:
return GetUndefinedDescriptor();
case ts.SyntaxKind.CallExpression:
return GetCallExpressionDescriptor(node as ts.CallExpression, scope);
default:
TransformerLogger().typeNotSupported(ts.SyntaxKind[node.kind]);
return GetNullDescriptor();
}
}
34 changes: 17 additions & 17 deletions src/transformer/descriptor/indexedAccess/indexedAccess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,28 @@ export function GetIndexedAccessTypeDescriptor(node: ts.IndexedAccessTypeNode, s
let propertyName: string | null = null;

switch (node.indexType.kind) {
case ts.SyntaxKind.TypeReference:
const declaration: ts.Declaration = TypescriptHelper.GetDeclarationFromNode((node.indexType as ts.TypeReferenceNode).typeName);
case ts.SyntaxKind.TypeReference:
const declaration: ts.Declaration = TypescriptHelper.GetDeclarationFromNode((node.indexType as ts.TypeReferenceNode).typeName);

switch (declaration.kind) {
case ts.SyntaxKind.TypeParameter:
const propertyNameIdentifier: ts.PropertyName = PropertySignatureCache.instance.get();
propertyName = (propertyNameIdentifier as ts.Identifier).escapedText as string;
switch (declaration.kind) {
case ts.SyntaxKind.TypeParameter:
const propertyNameIdentifier: ts.PropertyName = PropertySignatureCache.instance.get();
propertyName = (propertyNameIdentifier as ts.Identifier).escapedText as string;
break;
case ts.SyntaxKind.TypeAliasDeclaration:
propertyName = (((declaration as ts.TypeAliasDeclaration).type as ts.LiteralTypeNode).literal as ts.StringLiteral).text;
break;
default:
TransformerLogger().typeNotSupported('IndexedAccess of TypeReference of ' + ts.SyntaxKind[declaration.kind]);
break;
}
break;
case ts.SyntaxKind.TypeAliasDeclaration:
propertyName = (((declaration as ts.TypeAliasDeclaration).type as ts.LiteralTypeNode).literal as ts.StringLiteral).text;
case ts.SyntaxKind.LiteralType:
propertyName = ((node.indexType as ts.LiteralTypeNode).literal as ts.StringLiteral).text;
break;
default:
TransformerLogger().typeNotSupported('IndexedAccess of TypeReference of ' + ts.SyntaxKind[declaration.kind]);
TransformerLogger().typeNotSupported('IndexedAccess of ' + ts.SyntaxKind[node.indexType.kind]);
break;
}
break;
case ts.SyntaxKind.LiteralType:
propertyName = ((node.indexType as ts.LiteralTypeNode).literal as ts.StringLiteral).text;
break;
default:
TransformerLogger().typeNotSupported('IndexedAccess of ' + ts.SyntaxKind[node.indexType.kind]);
break;
}

if (propertyName !== null) {
Expand Down
16 changes: 10 additions & 6 deletions src/transformer/descriptor/method/bodyReturnType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,25 @@ import { Scope } from '../../scope/scope';
import { GetDescriptor } from '../descriptor';
import { GetNullDescriptor } from '../null/null';

export function GetReturnTypeFromBody(node: ts.ArrowFunction | ts.FunctionExpression | ts.MethodDeclaration | ts.FunctionDeclaration, scope: Scope): ts.Expression {
let returnValue: ts.Expression;
export function GetReturnTypeFromBodyDescriptor(node: ts.ArrowFunction | ts.FunctionExpression | ts.MethodDeclaration | ts.FunctionDeclaration, scope: Scope): ts.Expression {
return GetDescriptor(GetReturnNodeFromBody(node), scope);
}

export function GetReturnNodeFromBody(node: ts.FunctionLikeDeclaration): ts.Node {
let returnValue: ts.Node;

const functionBody: ts.FunctionBody = node.body as ts.FunctionBody;
const functionBody: ts.ConciseBody = node.body;

if (functionBody.statements) {
if (ts.isBlock(functionBody)) {
const returnStatement: ts.ReturnStatement = GetReturnStatement(functionBody);

if (returnStatement) {
returnValue = GetDescriptor(returnStatement.expression, scope);
returnValue = returnStatement.expression;
} else {
returnValue = GetNullDescriptor();
}
} else {
returnValue = GetDescriptor(node.body, scope);
returnValue = node.body;
}

return returnValue;
Expand Down
4 changes: 2 additions & 2 deletions src/transformer/descriptor/method/functionAssignment.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import * as ts from 'typescript';
import { Scope } from '../../scope/scope';
import { PropertySignatureCache } from '../property/cache';
import { GetReturnTypeFromBody } from './bodyReturnType';
import { GetReturnTypeFromBodyDescriptor } from './bodyReturnType';
import { GetMethodDescriptor } from './method';

type functionAssignment = ts.ArrowFunction | ts.FunctionExpression;

export function GetFunctionAssignmentDescriptor(node: functionAssignment, scope: Scope): ts.Expression {
const property: ts.PropertyName = PropertySignatureCache.instance.get();
const returnValue: ts.Expression = GetReturnTypeFromBody(node, scope);
const returnValue: ts.Expression = GetReturnTypeFromBodyDescriptor(node, scope);

return GetMethodDescriptor(property, returnValue);
}
14 changes: 14 additions & 0 deletions src/transformer/descriptor/method/functionReturnType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import * as ts from 'typescript';
import { GetReturnNodeFromBody } from './bodyReturnType';

export function GetFunctionReturnType(node: ts.FunctionLikeDeclaration): ts.Node {
let returnType: ts.Node;

if (node.type) {
returnType = node.type;
} else {
returnType = GetReturnNodeFromBody(node);
}

return returnType;
}
11 changes: 3 additions & 8 deletions src/transformer/descriptor/method/methodDeclaration.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import * as ts from 'typescript';
import { Scope } from '../../scope/scope';
import { GetDescriptor } from '../descriptor';
import { GetReturnTypeFromBody } from './bodyReturnType';
import { GetFunctionReturnType } from './functionReturnType';
import { GetMethodDescriptor } from './method';

export function GetMethodDeclarationDescriptor(node: ts.MethodDeclaration | ts.FunctionDeclaration, scope: Scope): ts.Expression {
let returnType: ts.Expression;

if (node.type) {
returnType = GetDescriptor(node.type, scope);
} else {
returnType = GetReturnTypeFromBody(node, scope);
}
const returnTypeNode: ts.Node = GetFunctionReturnType(node);
const returnType: ts.Expression = GetDescriptor(returnTypeNode, scope);

return GetMethodDescriptor(node.name, returnType);
}

0 comments on commit 3006c84

Please sign in to comment.