From cbbfd522d984fc61c4bee08c011a6a0da568f0bc Mon Sep 17 00:00:00 2001 From: Pmyl Date: Mon, 13 Jan 2020 20:37:18 +0000 Subject: [PATCH 1/3] perf(emit): decrease emitted code by using minification techniques and by not always using get/set for properties --- .../descriptor/boolean/booleanFalse.ts | 2 +- .../descriptor/boolean/booleanTrue.ts | 2 +- src/transformer/descriptor/mock/mockCall.ts | 27 +++++++++++--- src/transformer/descriptor/mock/mockMarker.ts | 3 +- .../descriptor/mock/mockProperties.ts | 8 +--- .../descriptor/mock/mockProperty.ts | 37 +++++++++++++++++-- .../descriptor/undefined/undefined.ts | 2 +- .../mockDefiner/factoryUniqueName.ts | 17 +++++---- 8 files changed, 72 insertions(+), 26 deletions(-) diff --git a/src/transformer/descriptor/boolean/booleanFalse.ts b/src/transformer/descriptor/boolean/booleanFalse.ts index 478e68d0d..7c5207cdf 100644 --- a/src/transformer/descriptor/boolean/booleanFalse.ts +++ b/src/transformer/descriptor/boolean/booleanFalse.ts @@ -1,5 +1,5 @@ import * as ts from 'typescript'; export function GetBooleanFalseDescriptor(): ts.Expression { - return ts.createLiteral(false); + return ts.createLogicalNot(ts.createLiteral(1)); } diff --git a/src/transformer/descriptor/boolean/booleanTrue.ts b/src/transformer/descriptor/boolean/booleanTrue.ts index 0aff537e5..a6f0b32df 100644 --- a/src/transformer/descriptor/boolean/booleanTrue.ts +++ b/src/transformer/descriptor/boolean/booleanTrue.ts @@ -1,5 +1,5 @@ import * as ts from 'typescript'; export function GetBooleanTrueDescriptor(): ts.Expression { - return ts.createLiteral(true); + return ts.createLogicalNot(ts.createLiteral(0)); } diff --git a/src/transformer/descriptor/mock/mockCall.ts b/src/transformer/descriptor/mock/mockCall.ts index ba74c3cba..2a7729163 100644 --- a/src/transformer/descriptor/mock/mockCall.ts +++ b/src/transformer/descriptor/mock/mockCall.ts @@ -1,23 +1,33 @@ import * as ts from 'typescript'; import { TypescriptCreator } from '../../helper/creator'; import { MockIdentifierInternalValues, MockIdentifierObjectReturnValue } from '../../mockIdentifier/mockIdentifier'; +import { TypescriptHelper } from '../helper/helper'; import { GetMockMarkerProperty, Property } from './mockMarker'; +import { PropertyAssignments } from './mockProperty'; -export function GetMockCall(properties: ts.PropertyAssignment[], signature: ts.Expression): ts.CallExpression { +export function GetMockCall(properties: PropertyAssignments, signature: ts.Expression): ts.CallExpression { const mockObjectReturnValueName: ts.Identifier = MockIdentifierObjectReturnValue; const statements: ts.Statement[] = [ ts.createVariableStatement([], [ TypescriptCreator.createVariableDeclaration(MockIdentifierInternalValues, ts.createObjectLiteral()), - TypescriptCreator.createVariableDeclaration(mockObjectReturnValueName, ts.createObjectLiteral()), + TypescriptCreator.createVariableDeclaration(mockObjectReturnValueName, signature || ts.createObjectLiteral(properties.literals)), ]), ]; if (signature) { - statements.push(AssignVariableTo(mockObjectReturnValueName, signature)); + let literalProperty: ts.PropertyAssignment; + let index: number = 0; + + // tslint:disable-next-line:no-conditional-assignment + while ((literalProperty = properties.literals[index++])) { + statements.push(AssignLiteralPropertyTo(mockObjectReturnValueName, literalProperty)); + } } - const addPropertiesToUniqueVariable: ts.ExpressionStatement = AssignPropertiesTo(properties, mockObjectReturnValueName); - statements.push(addPropertiesToUniqueVariable); + if (properties.lazy.length) { + const addPropertiesToUniqueVariable: ts.ExpressionStatement = AssignPropertiesTo(properties.lazy, mockObjectReturnValueName); + statements.push(addPropertiesToUniqueVariable); + } const addMockMarkerToUniqueVariable: ts.ExpressionStatement = AssignMockMarkerPropertyTo(mockObjectReturnValueName); statements.push(addMockMarkerToUniqueVariable); @@ -30,11 +40,16 @@ export function GetMockCall(properties: ts.PropertyAssignment[], signature: ts.E return ts.createCall(IFFEFunction, [], []); } -function AssignVariableTo(variable: ts.Identifier, expression: ts.Expression): ts.ExpressionStatement { +function AssignVariableTo(variable: ts.Expression, expression: ts.Expression): ts.ExpressionStatement { const binaryExpression: ts.BinaryExpression = ts.createBinary(variable, ts.SyntaxKind.EqualsToken, expression); return ts.createExpressionStatement(binaryExpression); } +function AssignLiteralPropertyTo(mockObjectReturnValueName: ts.Identifier, literalProperty: ts.PropertyAssignment): ts.ExpressionStatement { + const propertyAccess: ts.ElementAccessExpression = ts.createElementAccess(mockObjectReturnValueName, literalProperty.name as ts.StringLiteral); + return AssignVariableTo(propertyAccess, literalProperty.initializer); +} + function AssignMockMarkerPropertyTo(identifier: ts.Identifier): ts.ExpressionStatement { const mockMarkerProperty: Property = GetMockMarkerProperty(); diff --git a/src/transformer/descriptor/mock/mockMarker.ts b/src/transformer/descriptor/mock/mockMarker.ts index d60f76847..70048ee66 100644 --- a/src/transformer/descriptor/mock/mockMarker.ts +++ b/src/transformer/descriptor/mock/mockMarker.ts @@ -1,6 +1,7 @@ import * as ts from 'typescript'; import { MockDefiner } from '../../mockDefiner/mockDefiner'; import { ModuleName } from '../../mockDefiner/modules/moduleName'; +import { GetBooleanTrueDescriptor } from '../boolean/booleanTrue'; export interface Property { name: ts.Expression; @@ -21,6 +22,6 @@ export function GetMockMarkerProperty(): Property { return { name: mockMarkerCall, - value: ts.createLiteral(true), + value: GetBooleanTrueDescriptor(), }; } diff --git a/src/transformer/descriptor/mock/mockProperties.ts b/src/transformer/descriptor/mock/mockProperties.ts index 1dbe897c3..1fcc479b4 100644 --- a/src/transformer/descriptor/mock/mockProperties.ts +++ b/src/transformer/descriptor/mock/mockProperties.ts @@ -3,7 +3,7 @@ import { Scope } from '../../scope/scope'; import { GetDescriptor } from '../descriptor'; import { IsTypescriptType } from '../tsLibs/typecriptLibs'; import { GetMockCall } from './mockCall'; -import { GetMockProperty } from './mockProperty'; +import { GetMockProperties, PropertyAssignments } from './mockProperty'; import { PropertyLike } from './propertyLike'; import { SignatureLike } from './signatureLike'; @@ -36,11 +36,7 @@ export function GetMockPropertiesFromDeclarations(list: ReadonlyArray { - return GetMockProperty(member, scope); - }, - ); + const accessorDeclaration: PropertyAssignments = GetMockProperties(propertiesFilter, scope); const signaturesDescriptor: ts.Expression = signatures.length > 0 ? GetDescriptor(signatures[0], scope) : null; return GetMockCall(accessorDeclaration, signaturesDescriptor); diff --git a/src/transformer/descriptor/mock/mockProperty.ts b/src/transformer/descriptor/mock/mockProperty.ts index 33bf3fdc7..19c158087 100644 --- a/src/transformer/descriptor/mock/mockProperty.ts +++ b/src/transformer/descriptor/mock/mockProperty.ts @@ -2,13 +2,44 @@ import * as ts from 'typescript'; import { TypescriptCreator } from '../../helper/creator'; import { MockIdentifierInternalValues, MockIdentifierSetParameterName } from '../../mockIdentifier/mockIdentifier'; import { Scope } from '../../scope/scope'; +import { GetBooleanTrueDescriptor } from '../boolean/booleanTrue'; import { GetDescriptor } from '../descriptor'; import { TypescriptHelper } from '../helper/helper'; import { PropertyLike } from './propertyLike'; -export function GetMockProperty(member: PropertyLike, scope: Scope): ts.PropertyAssignment { - const descriptor: ts.Expression = GetDescriptor(member, scope); +export interface PropertyAssignments { + lazy: ts.PropertyAssignment[]; + literals: ts.PropertyAssignment[]; +} + +export function GetMockProperties(properties: PropertyLike[], scope: Scope): PropertyAssignments { + return properties.reduce( + (acc: PropertyAssignments, member: PropertyLike): PropertyAssignments => { + const descriptor: ts.Expression = GetDescriptor(member, scope); + + if (descriptor.kind === ts.SyntaxKind.VoidExpression) { + return acc; + } + + if (ts.isCallLikeExpression(descriptor)) { + acc.lazy.push(GetLazyMockProperty(descriptor, member)); + } else { + acc.literals.push(GetLiteralMockProperty(descriptor, member)); + } + + return acc; + }, + { lazy: [], literals: []}, + ); +} + +function GetLiteralMockProperty(descriptor: ts.Expression, member: PropertyLike): ts.PropertyAssignment { + const propertyName: string = TypescriptHelper.GetStringPropertyName(member.name); + + return ts.createPropertyAssignment(ts.createStringLiteral(propertyName), descriptor); +} +function GetLazyMockProperty(descriptor: ts.Expression, member: PropertyLike): ts.PropertyAssignment { const propertyName: string = TypescriptHelper.GetStringPropertyName(member.name); const variableDeclarationName: ts.ElementAccessExpression = ts.createElementAccess(MockIdentifierInternalValues, ts.createStringLiteral(propertyName)); @@ -29,7 +60,7 @@ export function GetMockProperty(member: PropertyLike, scope: Scope): ts.Property const set: ts.MethodDeclaration = TypescriptCreator.createMethod('set', setBody, [setVariableParameterName]); const literal: ts.ObjectLiteralExpression = ts.createObjectLiteral([get, set, ts.createPropertyAssignment( ts.createIdentifier('enumerable'), - ts.createTrue(), + GetBooleanTrueDescriptor(), )]); return ts.createPropertyAssignment(ts.createStringLiteral(propertyName), literal); diff --git a/src/transformer/descriptor/undefined/undefined.ts b/src/transformer/descriptor/undefined/undefined.ts index b52b58924..81abe53a3 100644 --- a/src/transformer/descriptor/undefined/undefined.ts +++ b/src/transformer/descriptor/undefined/undefined.ts @@ -1,5 +1,5 @@ import * as ts from 'typescript'; export function GetUndefinedDescriptor(): ts.Expression { - return ts.createIdentifier('undefined'); + return ts.createVoidZero(); } diff --git a/src/transformer/mockDefiner/factoryUniqueName.ts b/src/transformer/mockDefiner/factoryUniqueName.ts index ae5462a0c..bb4999a3c 100644 --- a/src/transformer/mockDefiner/factoryUniqueName.ts +++ b/src/transformer/mockDefiner/factoryUniqueName.ts @@ -4,6 +4,8 @@ import { KeyCounter } from './keyCounter'; export type PossibleDeclaration = ts.InterfaceDeclaration | ts.ClassDeclaration | ts.TypeAliasDeclaration; export class FactoryUniqueName { + private static AnonymousIdentifierText: string = '*'; + private static LiteralIdentifierText: string = 'L'; private _keyCounter: KeyCounter; constructor() { @@ -12,17 +14,14 @@ export class FactoryUniqueName { public createForDeclaration(declaration: PossibleDeclaration): string { const declarationNameIdentifier: ts.Identifier = declaration.name; - const declarationNameSanitized: string = (declarationNameIdentifier && declarationNameIdentifier.text) || 'Anonymous'; - const baseFactoryName: string = `create__${declarationNameSanitized}__mock`; - const count: number = this._keyCounter.getFor(baseFactoryName); - return `${baseFactoryName}_${count}`; + return this.createUniqueName(declarationNameIdentifier && declarationNameIdentifier.text); } public createForIntersection(nodes: ts.Node[]): string { const nameOfDeclarations: string = nodes.reduce((acc: string, declaration: ts.Node) => { if (ts.isTypeLiteralNode(declaration)) { - acc += 'literal'; + acc += FactoryUniqueName.LiteralIdentifierText; } if (ts.isInterfaceDeclaration(declaration) || ts.isTypeAliasDeclaration(declaration) || ts.isClassDeclaration(declaration)) { @@ -32,8 +31,12 @@ export class FactoryUniqueName { return acc; }, ''); - const declarationNameSanitized: string = nameOfDeclarations || 'Anonymous'; - const baseFactoryName: string = `create__${declarationNameSanitized}__mock`; + return this.createUniqueName(nameOfDeclarations); + } + + private createUniqueName(name?: string): string { + const declarationNameSanitized: string = name || FactoryUniqueName.AnonymousIdentifierText; + const baseFactoryName: string = `@${declarationNameSanitized}`; const count: number = this._keyCounter.getFor(baseFactoryName); return `${baseFactoryName}_${count}`; From 123d04a1552bb4eeb01764bb679252b85468789f Mon Sep 17 00:00:00 2001 From: Pmyl Date: Tue, 14 Jan 2020 13:37:57 +0000 Subject: [PATCH 2/3] move string constants in the same file as identifier constants, rename mockProperty file so that it reflects its new purpose --- src/transformer/descriptor/mock/mockProperties.ts | 4 ++-- .../mock/{mockProperty.ts => mockPropertiesAssignments.ts} | 2 +- src/transformer/mockDefiner/factoryUniqueName.ts | 7 +++---- src/transformer/mockIdentifier/mockIdentifier.ts | 2 ++ 4 files changed, 8 insertions(+), 7 deletions(-) rename src/transformer/descriptor/mock/{mockProperty.ts => mockPropertiesAssignments.ts} (96%) diff --git a/src/transformer/descriptor/mock/mockProperties.ts b/src/transformer/descriptor/mock/mockProperties.ts index 1fcc479b4..9ea2e1546 100644 --- a/src/transformer/descriptor/mock/mockProperties.ts +++ b/src/transformer/descriptor/mock/mockProperties.ts @@ -3,7 +3,7 @@ import { Scope } from '../../scope/scope'; import { GetDescriptor } from '../descriptor'; import { IsTypescriptType } from '../tsLibs/typecriptLibs'; import { GetMockCall } from './mockCall'; -import { GetMockProperties, PropertyAssignments } from './mockProperty'; +import { GetMockPropertiesAssignments, PropertyAssignments } from './mockPropertiesAssignments'; import { PropertyLike } from './propertyLike'; import { SignatureLike } from './signatureLike'; @@ -36,7 +36,7 @@ export function GetMockPropertiesFromDeclarations(list: ReadonlyArray 0 ? GetDescriptor(signatures[0], scope) : null; return GetMockCall(accessorDeclaration, signaturesDescriptor); diff --git a/src/transformer/descriptor/mock/mockProperty.ts b/src/transformer/descriptor/mock/mockPropertiesAssignments.ts similarity index 96% rename from src/transformer/descriptor/mock/mockProperty.ts rename to src/transformer/descriptor/mock/mockPropertiesAssignments.ts index 19c158087..bbe301fe2 100644 --- a/src/transformer/descriptor/mock/mockProperty.ts +++ b/src/transformer/descriptor/mock/mockPropertiesAssignments.ts @@ -12,7 +12,7 @@ export interface PropertyAssignments { literals: ts.PropertyAssignment[]; } -export function GetMockProperties(properties: PropertyLike[], scope: Scope): PropertyAssignments { +export function GetMockPropertiesAssignments(properties: PropertyLike[], scope: Scope): PropertyAssignments { return properties.reduce( (acc: PropertyAssignments, member: PropertyLike): PropertyAssignments => { const descriptor: ts.Expression = GetDescriptor(member, scope); diff --git a/src/transformer/mockDefiner/factoryUniqueName.ts b/src/transformer/mockDefiner/factoryUniqueName.ts index bb4999a3c..0576c382d 100644 --- a/src/transformer/mockDefiner/factoryUniqueName.ts +++ b/src/transformer/mockDefiner/factoryUniqueName.ts @@ -1,11 +1,10 @@ import * as ts from 'typescript'; +import { MockCallAnonymousText, MockCallLiteralText } from '../mockIdentifier/mockIdentifier'; import { KeyCounter } from './keyCounter'; export type PossibleDeclaration = ts.InterfaceDeclaration | ts.ClassDeclaration | ts.TypeAliasDeclaration; export class FactoryUniqueName { - private static AnonymousIdentifierText: string = '*'; - private static LiteralIdentifierText: string = 'L'; private _keyCounter: KeyCounter; constructor() { @@ -21,7 +20,7 @@ export class FactoryUniqueName { public createForIntersection(nodes: ts.Node[]): string { const nameOfDeclarations: string = nodes.reduce((acc: string, declaration: ts.Node) => { if (ts.isTypeLiteralNode(declaration)) { - acc += FactoryUniqueName.LiteralIdentifierText; + acc += MockCallLiteralText; } if (ts.isInterfaceDeclaration(declaration) || ts.isTypeAliasDeclaration(declaration) || ts.isClassDeclaration(declaration)) { @@ -35,7 +34,7 @@ export class FactoryUniqueName { } private createUniqueName(name?: string): string { - const declarationNameSanitized: string = name || FactoryUniqueName.AnonymousIdentifierText; + const declarationNameSanitized: string = name || MockCallAnonymousText; const baseFactoryName: string = `@${declarationNameSanitized}`; const count: number = this._keyCounter.getFor(baseFactoryName); diff --git a/src/transformer/mockIdentifier/mockIdentifier.ts b/src/transformer/mockIdentifier/mockIdentifier.ts index 572c76047..59e7e96eb 100644 --- a/src/transformer/mockIdentifier/mockIdentifier.ts +++ b/src/transformer/mockIdentifier/mockIdentifier.ts @@ -6,3 +6,5 @@ export const MockIdentifierGenericParameterValue: ts.Identifier = ts.createIdent export const MockIdentifierInternalValues: ts.Identifier = ts.createIdentifier('d'); export const MockIdentifierObjectReturnValue: ts.Identifier = ts.createIdentifier('m'); export const MockIdentifierSetParameterName: ts.Identifier = ts.createIdentifier('v'); +export const MockCallAnonymousText: string = '*'; +export const MockCallLiteralText: string = 'L'; From 315ca75098e42eb0684e4eebc67a3abca55d254c Mon Sep 17 00:00:00 2001 From: Pmyl Date: Tue, 14 Jan 2020 13:44:18 +0000 Subject: [PATCH 3/3] fix import --- src/transformer/descriptor/mock/mockCall.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/transformer/descriptor/mock/mockCall.ts b/src/transformer/descriptor/mock/mockCall.ts index 2a7729163..c87d3b537 100644 --- a/src/transformer/descriptor/mock/mockCall.ts +++ b/src/transformer/descriptor/mock/mockCall.ts @@ -1,9 +1,8 @@ import * as ts from 'typescript'; import { TypescriptCreator } from '../../helper/creator'; import { MockIdentifierInternalValues, MockIdentifierObjectReturnValue } from '../../mockIdentifier/mockIdentifier'; -import { TypescriptHelper } from '../helper/helper'; import { GetMockMarkerProperty, Property } from './mockMarker'; -import { PropertyAssignments } from './mockProperty'; +import { PropertyAssignments } from './mockPropertiesAssignments'; export function GetMockCall(properties: PropertyAssignments, signature: ts.Expression): ts.CallExpression { const mockObjectReturnValueName: ts.Identifier = MockIdentifierObjectReturnValue;