Skip to content

Commit

Permalink
feat: implement extend decorator
Browse files Browse the repository at this point in the history
  • Loading branch information
Velmisov committed Jul 19, 2020
1 parent 37f8263 commit e39c775
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 0 deletions.
23 changes: 23 additions & 0 deletions src/extend.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import 'reflect-metadata';
import { extendRecursively } from './utils';

export function Extend(): ClassDecorator {
return (constructor: Function): void => {
const instance: Object = constructor.prototype;
const instanceProto: Object = Object.getPrototypeOf(instance);

for (const propertyKey of Object.getOwnPropertyNames(instance)) {
const metadataKeys =
propertyKey === 'constructor'
? Reflect.getOwnMetadataKeys(instance.constructor)
: Reflect.getOwnMetadataKeys(instance, propertyKey);

extendRecursively(
instance,
metadataKeys,
propertyKey,
instanceProto,
);
}
};
}
81 changes: 81 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
export function extendRecursively(
instance: Object,
metadataKeys: any[], // eslint-disable-line
propertyKey: string | symbol,
instanceProto: Object,
): void {
if (propertyKey === 'constructor')
extendConstructorRec(instance, metadataKeys, instanceProto);
else extendPropertyRec(instance, metadataKeys, propertyKey, instanceProto);
}

function extendConstructorRec(
instance: Object,
metadataKeys: any[], // eslint-disable-line
instanceProto: Object,
) {
if (!instanceProto || !instanceProto.constructor) return;

const protoMetadataKeys = Reflect.getOwnMetadataKeys(
instanceProto.constructor,
);
for (const metadataKey of protoMetadataKeys) {
if (metadataKeys.includes(metadataKey)) continue;

const metadataValue = Reflect.getOwnMetadata(
metadataKey,
instanceProto.constructor,
);

Reflect.defineMetadata(
metadataKey,
metadataValue,
instance.constructor,
);
metadataKeys.push(metadataKey);
}

extendConstructorRec(
instance,
metadataKeys,
Object.getPrototypeOf(instanceProto),
);
}

function extendPropertyRec(
instance: Object,
metadataKeys: any[], // eslint-disable-line
propertyKey: string | symbol,
instanceProto: Object,
) {
if (!instanceProto || !instanceProto.hasOwnProperty(propertyKey)) return;

const protoMetadataKeys = Reflect.getOwnMetadataKeys(
instanceProto,
propertyKey,
);
for (const metadataKey of protoMetadataKeys) {
if (metadataKeys.includes(metadataKey)) continue;

const metadataValue = Reflect.getOwnMetadata(
metadataKey,
instanceProto,
propertyKey,
);

Reflect.defineMetadata(
metadataKey,
metadataValue,
instance,
propertyKey,
);
metadataKeys.push(metadataKey);
}

extendPropertyRec(
instance,
metadataKeys,
propertyKey,
Object.getPrototypeOf(instanceProto),
);
}

0 comments on commit e39c775

Please sign in to comment.