Skip to content

Commit

Permalink
Add LanguageExtension/PrototypeReflect.
Browse files Browse the repository at this point in the history
  • Loading branch information
aioutecism committed Apr 14, 2016
1 parent c58e9c0 commit 0d875ed
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 0 deletions.
110 changes: 110 additions & 0 deletions src/LanguageExtension/PrototypeReflect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
function isObject(x: any): boolean {
return typeof x === 'object' ? x !== null : typeof x === 'function';
}

function isUndefined(x: any): boolean {
return x === undefined;
}

function isConstructor(x: any): boolean {
return typeof x === 'function';
}

function isPrototypeExists(x: any): boolean {
return x !== null
&& x !== undefined
&& x.prototype !== null
&& x.prototype !== undefined;
}

/**
* Prototype version of https://github.com/rbuckton/ReflectDecorators/ (Partial)
* Save metadata in prototype so we can get it without context.
*/
export class PrototypeReflect {

private static metadataKey = Symbol('ReflectMetadata');

/**
* A default metadata decorator factory that can be used on a class, class member, or parameter.
* @param metadataKey The key for the metadata entry.
* @param metadataValue The value for the metadata entry.
* @returns A decorator function.
* @remarks
* If `metadataKey` is already defined for the target and target key, the
* metadataValue for that key will be overwritten.
* @example
*
* // constructor
* @PrototypeReflect.metadata(key, value)
* class C {
* }
*
* // property (on constructor)
* class C {
* @PrototypeReflect.metadata(key, value)
* static staticProperty;
* }
*
* // property (on prototype)
* class C {
* @PrototypeReflect.metadata(key, value)
* property;
* }
*
* // method (on constructor)
* class C {
* @PrototypeReflect.metadata(key, value)
* static staticMethod() { }
* }
*
* // method (on prototype)
* class C {
* @PrototypeReflect.metadata(key, value)
* method() { }
* }
*/
static metadata(key: string | symbol, value: any) {
function decorator(targetObject: Function): void;
function decorator(targetObject: Object, targetKey: string | symbol): void;
function decorator(targetObject: Object, targetKey?: string | symbol): void {
if (!isUndefined(targetKey)) {
if (!isObject(targetObject)) {
throw new TypeError();
}
PrototypeReflect.defineMetadata(key, value, targetObject[targetKey]);
}
else {
if (!isConstructor(targetObject)) {
throw new TypeError();
}
PrototypeReflect.defineMetadata(key, value, targetObject);
}
};

return decorator;
}

static defineMetadata(key: string | symbol, value: any, target: any): void {
if (!isPrototypeExists(target)) {
throw new TypeError();
}

if (target.prototype[PrototypeReflect.metadataKey] === undefined) {
target.prototype[PrototypeReflect.metadataKey] = {};
}

target.prototype[PrototypeReflect.metadataKey][key] = value;
}

static getMetadata(key: string | symbol, target: any): any {
if (!isPrototypeExists(target)) {
throw new TypeError();
}

return (target.prototype[PrototypeReflect.metadataKey] === undefined)
? undefined
: target.prototype[PrototypeReflect.metadataKey][key];
}

}
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"experimentalDecorators": true,
"outDir": "out",
"noLib": true,
"sourceMap": true,
Expand Down

0 comments on commit 0d875ed

Please sign in to comment.