Skip to content

Commit

Permalink
refactor: god rid of some redundant checks, change class-type name, c…
Browse files Browse the repository at this point in the history
…hange tsconfig target
  • Loading branch information
omermorad committed Jan 25, 2021
1 parent 612adc0 commit 125c70a
Show file tree
Hide file tree
Showing 16 changed files with 59 additions and 49 deletions.
8 changes: 3 additions & 5 deletions src/class-processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import { EnumValueHandler } from './handlers/enum-value-handler';
import { MultiClassValueHandler } from './handlers/multi-class-value-handler';
import { SingleClassValueHandler } from './handlers/single-class-value-handler';
import { PrimitiveValueHandler } from './handlers/primitive-value-handler';
import { ClassLiteral, ClassType, FixtureOptions } from './types/fixture-options.type';
import { ClassLiteral, Class, FixtureOptions } from './types/fixture-options.type';
import { PropertyDto } from './types/property-dto.interface';
import { ValueHandler } from './types/value-handler.interface';
import { IClassProcessor } from './types/iclass-processor.interface';

import FakerStatic = Faker.FakerStatic;

export class ClassProcessor<T> implements IClassProcessor<T> {
private static readonly VALUE_INSPECTORS: ClassType<ValueHandler<FixtureOptions>>[] = [
private static readonly VALUE_INSPECTORS: Class<ValueHandler<FixtureOptions>>[] = [
EnumValueHandler,
MultiClassValueHandler,
SingleClassValueHandler,
Expand All @@ -36,8 +36,6 @@ export class ClassProcessor<T> implements IClassProcessor<T> {
return inspector.produceValue<T>(propertyDto);
}
}

return null;
}

/**
Expand All @@ -46,7 +44,7 @@ export class ClassProcessor<T> implements IClassProcessor<T> {
*
* @param target
*/
public process(target: ClassType<T>): ClassLiteral<T> {
public process(target: Class<T>): ClassLiteral<T> {
if (!target) {
throw new Error(`Target class '${target}' is 'undefined'`);
}
Expand Down
13 changes: 8 additions & 5 deletions src/class-reflector.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import reflect, { ClassReflection, PropertyReflection } from '@plumier/reflect';
import { ClassType } from './types/fixture-options.type';
import { Class } from './types/fixture-options.type';
import { FixtureOptions } from './types/fixture-options.type';
import { FIXTURE_DECORATOR_NAME } from './decorators/fixture.decorator';
import { PropertyDto } from './types/property-dto.interface';
Expand All @@ -9,7 +9,7 @@ export class ClassReflector {
public static readonly REFLECTED_CLASSES: Record<string, ClassReflectionDto> = {};

private extractDecoratedProperties(classReflection: ClassReflection): PropertyDto<FixtureOptions>[] {
return classReflection.properties?.map((property) => {
return classReflection.properties.map((property) => {
const value = ClassReflector.extractFixtureDecoratorValue(property);
return ClassReflector.createPropertyDto(property, value);
});
Expand All @@ -19,7 +19,10 @@ export class ClassReflector {
property: PropertyReflection,
fixtureDecoratorValue: FixtureOptions | null
): PropertyDto<FixtureOptions> {
const { name, type: { name: constructorName } = {} } = property;
const {
name,
type: { name: constructorName },
} = property;

return {
type: typeof fixtureDecoratorValue,
Expand All @@ -30,13 +33,13 @@ export class ClassReflector {
}

private static extractFixtureDecoratorValue(property: PropertyReflection): FixtureOptions | null {
const { decorators = [] } = property;
const { decorators } = property;
const fixtureDecorator = decorators.find((decorator) => decorator.type === FIXTURE_DECORATOR_NAME);

return fixtureDecorator ? fixtureDecorator.value : null;
}

public reflectClass(target: ClassType<unknown>): ClassReflectionDto {
public reflectClass(target: Class<unknown>): ClassReflectionDto {
if (!ClassReflector.REFLECTED_CLASSES.hasOwnProperty(target.name)) {
ClassReflector.REFLECTED_CLASSES[target.name] = this.extractDecoratedProperties(reflect(target));
}
Expand Down
4 changes: 2 additions & 2 deletions src/decorators/fixture.decorator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'reflect-metadata';
import { decorateProperty } from '@plumier/reflect';
import { Callback, ClassType, EnumObject, ExactValue, MultiClass } from '../types/fixture-options.type';
import { Callback, Class, EnumObject, ExactValue, MultiClass } from '../types/fixture-options.type';
import { FixtureOptions } from '../types/fixture-options.type';

export const FIXTURE_DECORATOR_NAME = 'Fixture';
Expand Down Expand Up @@ -47,7 +47,7 @@ export function Fixture(value: ExactValue): PropertyDecorator;
* @param value
* @constructor
*/
export function Fixture(value: ClassType): PropertyDecorator;
export function Fixture(value: Class): PropertyDecorator;

/**
* Generate a random value from the given enum
Expand Down
2 changes: 1 addition & 1 deletion src/factories/fixture-factory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ describe('Fixture Factory - Unit', () => {
describe('given a Fixture Factory', () => {
class TestClass {}

describe("when calling 'create' method without extra options { count: 3 }", () => {
describe("when calling 'create' method without options", () => {
test('then call process exactly once', () => {
FixtureFactory.create(TestClass);

Expand Down
8 changes: 4 additions & 4 deletions src/factories/fixture-factory.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import faker from 'faker';
import { ClassProcessor } from '../class-processor';
import { ClassLiteral, ClassType } from '../types/fixture-options.type';
import { ClassLiteral, Class } from '../types/fixture-options.type';
import { FixtureFactoryOptions } from '../types';
import { ClassReflector } from '../class-reflector';

Expand All @@ -14,7 +14,7 @@ export class FixtureFactory {
*
* @param target
*/
public static create<T = unknown>(target: ClassType<T>): ClassLiteral<T>;
public static create<T = unknown>(target: Class<T>): ClassLiteral<T>;

/**
* Return an array of objects with all the properties decorated by the
Expand All @@ -32,7 +32,7 @@ export class FixtureFactory {
* @param target
* @param options
*/
public static create<T = unknown>(target: ClassType<T>, options: FixtureFactoryOptions): ClassLiteral<T>[];
public static create<T = unknown>(target: Class<T>, options: FixtureFactoryOptions): ClassLiteral<T>[];

/**
* Return one or many objects (array) with all the properties decorated
Expand All @@ -42,7 +42,7 @@ export class FixtureFactory {
* @param options
*/
public static create<T = unknown>(
target: ClassType<T>,
target: Class<T>,
options?: FixtureFactoryOptions
): ClassLiteral<T> | ClassLiteral<T>[] {
const { count = 1, locale = ClassProcessor.DEFAULT_LOCALE } = options || {};
Expand Down
2 changes: 1 addition & 1 deletion src/handlers/enum-value-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export class EnumValueHandler<P extends EnumObject> implements ValueHandler<P> {
}

public static isEnumValue(propertyDto: PropertyDto<EnumObject>): boolean {
const { value = '' } = propertyDto;
const { value } = propertyDto;

return Object.prototype.hasOwnProperty.call(value, 'enum');
}
Expand Down
13 changes: 5 additions & 8 deletions src/handlers/multi-class-value-handler.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ValueHandler } from '../types/value-handler.interface';
import { PropertyDto } from '../types/property-dto.interface';
import { ExactValue, ClassType } from '../types/fixture-options.type';
import { ExactValue, Class } from '../types/fixture-options.type';
import { MultiClass } from '../types/fixture-options.type';
import { ClassProcessor } from '../class-processor';
import { PrimitiveHandlerAbstract } from './primitive-handler-abstract';
Expand All @@ -10,15 +10,12 @@ import FakerStatic = Faker.FakerStatic;
export class MultiClassValueHandler<P extends MultiClass>
extends PrimitiveHandlerAbstract<P>
implements ValueHandler<P> {
public constructor(
protected readonly faker: FakerStatic,
protected readonly classProcessor: ClassProcessor<ClassType>
) {
public constructor(protected readonly faker: FakerStatic, protected readonly classProcessor: ClassProcessor<Class>) {
super(faker);
}

public static isTypeValue(propertyDto: PropertyDto<MultiClass>): boolean {
const { value = '' } = propertyDto;
public static isTypeValue(propertyDto: PropertyDto<any>): boolean {
const { value } = propertyDto;

return Object.prototype.hasOwnProperty.call(value, 'type');
}
Expand Down Expand Up @@ -49,7 +46,7 @@ export class MultiClassValueHandler<P extends MultiClass>
const instances = new Array(count);

for (let index = 0; index < count; index++) {
instances[index] = this.classProcessor.process(type);
instances[index] = this.classProcessor.process(type as Class);
}

return instances;
Expand Down
3 changes: 2 additions & 1 deletion src/handlers/object-literal-value-handler.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { ObjectLiteralValueHandler } from '../handlers/object-literal-value-handler';
import { ObjectLiteral } from '../types/fixture-options.type';

describe('ObjectLiteralValueInspector Unit', () => {
let dto, handler: ObjectLiteralValueHandler<object>;
let dto, handler: ObjectLiteralValueHandler<ObjectLiteral>;

const OBJECT_LITERAL_VALUE = { testArbitrary: 'and-arbitrary-value' };

Expand Down
8 changes: 4 additions & 4 deletions src/handlers/object-literal-value-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import { MultiClassValueHandler } from './multi-class-value-handler';
import { EnumValueHandler } from './enum-value-handler';
import { ValueHandler } from '../types/value-handler.interface';
import { PropertyDto } from '../types/property-dto.interface';
import { EnumObject, MultiClass } from '../types/fixture-options.type';
import { EnumObject, MultiClass, ObjectLiteral } from '../types/fixture-options.type';

export class ObjectLiteralValueHandler<P extends object> implements ValueHandler<P> {
export class ObjectLiteralValueHandler<P extends ObjectLiteral> implements ValueHandler<P> {
public shouldHandle(propertyDto: PropertyDto<P>): boolean {
return (
propertyDto.type === 'object' &&
!MultiClassValueHandler.isTypeValue(propertyDto as PropertyDto<MultiClass>) &&
!EnumValueHandler.isEnumValue(propertyDto as PropertyDto<EnumObject>)
!MultiClassValueHandler.isTypeValue((propertyDto as unknown) as PropertyDto<MultiClass>) &&
!EnumValueHandler.isEnumValue((propertyDto as unknown) as PropertyDto<EnumObject>)
);
}

Expand Down
2 changes: 1 addition & 1 deletion src/handlers/primitive-value-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export class PrimitiveValueHandler<P extends ExactValue>
const { value } = propertyDto;

if (typeof value !== 'undefined') {
if (MultiClassValueHandler.isTypeValue(propertyDto as PropertyDto<MultiClass>)) {
if (MultiClassValueHandler.isTypeValue((propertyDto as unknown) as PropertyDto<MultiClass>)) {
throw new Error(
'Type mismatch. Properties decorated with @Fixture({ type: ClassType }) must be typed as array (e.g. prop: string[])'
);
Expand Down
6 changes: 3 additions & 3 deletions src/handlers/single-class-value-handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { SingleClassValueHandler } from '../handlers/single-class-value-handler'
import { ClassProcessor } from '../class-processor';

import FakerStatic = Faker.FakerStatic;
import { ClassType } from 'src/types';
import { Class } from 'src/types';

describe('SingleClassValueInspector Unit', () => {
let handler: SingleClassValueHandler<ClassType>;
let handler: SingleClassValueHandler<Class>;
const DTO_CLASS_VALUE = class TestClass {};

const dto: PropertyDto<ClassType> = {
const dto: PropertyDto<Class> = {
type: 'function',
value: DTO_CLASS_VALUE,
name: 'testPropertyName',
Expand Down
6 changes: 2 additions & 4 deletions src/handlers/single-class-value-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@ import { PrimitiveHandlerAbstract } from './primitive-handler-abstract';
import { ClassProcessor } from '../class-processor';
import { ValueHandler } from '../types/value-handler.interface';
import { PropertyDto } from '../types/property-dto.interface';
import { ClassType } from '../types/fixture-options.type';
import { Class } from '../types/fixture-options.type';

import FakerStatic = Faker.FakerStatic;

export class SingleClassValueHandler<P extends ClassType>
extends PrimitiveHandlerAbstract<P>
implements ValueHandler<P> {
export class SingleClassValueHandler<P extends Class> extends PrimitiveHandlerAbstract<P> implements ValueHandler<P> {
public constructor(protected readonly faker: FakerStatic, protected readonly classProcessor: ClassProcessor<any>) {
super(faker);
}
Expand Down
12 changes: 8 additions & 4 deletions src/types/fixture-options.type.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
export type ExactValue = string | number | boolean | object;
export type MultiClass = { type: ClassType; count: number };
export interface ObjectLiteral {
[key: string]: unknown;
}

export type ExactValue = string | number | boolean | ObjectLiteral | Date;
export type MultiClass = { type: Class; count: number };
export type EnumObject = { enum: object };
export type Callback = (faker: Faker.FakerStatic) => any;

export interface ClassType<T = any> extends Function {
export interface Class<T = any> extends Function {
new (...args: any[]): T;
}

export type ClassLiteral<T> = Partial<{ [K in keyof T]: T[K] }>;

export type FixtureOptions = Callback | ExactValue | ClassType | EnumObject | MultiClass;
export type FixtureOptions = Callback | ExactValue | Class | EnumObject | MultiClass;
4 changes: 2 additions & 2 deletions src/types/iclass-processor.interface.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ClassLiteral, ClassType } from './fixture-options.type';
import { ClassLiteral, Class } from './fixture-options.type';

// eslint-disable-next-line @typescript-eslint/interface-name-prefix
export interface IClassProcessor<T> {
process(target: ClassType<T>): ClassLiteral<T>;
process(target: Class<T>): ClassLiteral<T>;
}
13 changes: 12 additions & 1 deletion test/integration/fixture-decorator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ describe('Fixture Factory - Integration Test', () => {
result = FixtureFactory.create(TestClassWithMultiClass);
});

test("then return array with length 'count'", () => {
test("then return contain a property 'dogs' which is array of Dog with length of 'count'", () => {
expect(result.dogs).toBeInstanceOf(Array);
expect(result.dogs).toHaveLength(3);
});
Expand All @@ -88,5 +88,16 @@ describe('Fixture Factory - Integration Test', () => {
);
});
});

describe("when using the related decorator with 'count' option", () => {
beforeAll(() => {
result = FixtureFactory.create(TestClassWithAbsoluteValues, { count: 4 });
});

test("then return array with length of 'count'", () => {
expect(result).toBeInstanceOf(Array);
expect(result).toHaveLength(4);
});
});
});
});
4 changes: 1 addition & 3 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"removeComments": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es2017",
"target": "es5",
"sourceMap": true,
"baseUrl": "./",
"outDir": "./dist",
Expand All @@ -29,10 +29,8 @@
"exclude": [
"index.ts",
"node_modules",
"sample",
"dist",
"test",
"env",
"coverage"
]
}

0 comments on commit 125c70a

Please sign in to comment.